State History
The StateHistoryPlugin
provides a convenient way for undo
and redo
functionality, saving you the trouble of maintaining a history in the app yourself.
To use it you should instantiate a new StateHistoryPlugin
object, passing the Query
:
import { StateHistoryPlugin } from '@datorama/akita';
export class TodosPageComponent {
private stateHistory: StateHistoryPlugin;
constructor(private todosQuery: TodosQuery) {}
ngOnInit() {
this.stateHistory = new StateHistoryPlugin(this.todosQuery);
}
}
From the moment you call it, Akita's StateHistory
tracks the history of the store and gives you the following functionality:
API
undo()
undo the last change.
redo()
redo the last change.
jump()
jump n steps in the past or forward.
jumpToPast(index: number)
jump to the provided index in the past (assuming index is valid).
jumpToFuture(index: number)
jump to the provided index in the future (assuming index is valid).
clear()
clear the history.
ignoreNext()
ignores the next store's update call. You should call it before updating the store.
destroy(clearHistory = false)
unsubscribe and optionally clear the history.
hasPast()
A boolean flag that returns whether the history is not empty.
hasFuture()
A boolean flag that returns whether you're not in the latest step in the history.
hasPast$
An observable that returns whether the history is not empty.
hasFuture$
An observable that returns whether you're not in the latest step in the history.
Options
maxAge
Maximum amount of changes to be stored in the history (default: 10):
const options = { maxAge: 3 };
stateHistory = new StateHistoryPlugin(todosQuery, options);
watchProperty
Watch a specific property:
const options = { watchProperty: 'editorText' };
stateHistory = new StateHistoryPlugin(editorQuery, options);
EntityStateHistoryPlugin
In addition to the general history functionality, Akita also provides a powerful API to help keep track of one or many entities, instead of the entire store.
A good example is when you have a table or a list of entities that the users can modify, and you want to give them a way to undo/redo their changes per entity. Here is how you can do it:
import { EntityStateHistoryPlugin } from '@datorama/akita';
export class TodosPageComponent {
private collection: EntityStateHistoryPlugin;
constructor(private todosQuery: TodosQuery) {}
ngOnInit() {
this.collection = new EntityStateHistoryPlugin(this.todosQuery);
}
}
With this setup you will get the following functionality:
API
type IDS = ID | ID[]
;
undo(entityId?: IDS)
undo the last change.
redo(entityId?: IDS)
redo the last change.
jumpToPast(entityId?: IDS, index: number)
jump to the provided index in the past (assuming index is valid).
jumpToFuture(entityId?: IDS, index: number)
jump to the provided index in the future (assuming index is valid).
clear(entityId?: IDS)
clear the history.
destroy(entityId?: IDS, clearHistory = false)
unsubscribe and optionally clear the history.
hasPast(entityId: ID)
A boolean flag that returns whether the history is not empty.
hasFuture(entityId: ID)
A boolean flag that returns whether you're not in the latest step in the history.
Options
maxAge
Maximum amount of changes to be stored in the history (default: 10):
const options = { maxAge: 3 };
stateHistory = new StateHistoryEntityPlugin(todosQuery, options);
entityIds
A single id or an array of entity ids (default: all).
const options = { entityIds: [1, 2] };
stateHistory = new StateHistoryEntityPlugin(editorQuery, options);
Here's a complete example:
<table>
<tbody>
<tr *ngFor="let todo of todos$ | async">
<td>{{todo.title}}</td>
<td>
<input type="checkbox" [checked]="todo.completed"
(change)="update($event, todo)"/>
</td>
<td>
<i
[class.disabled]="!stateHistoryEntity.hasPast(todo.id)"
(click)="stateHistoryEntity.undo(todo.id)">undo</i>
</td>
<td>
<i
[class.disabled]="!stateHistoryEntity.hasFuture(todo.id)"
(click)="stateHistoryEntity.redo(todo.id)">redo</i>
</td>
</tr>
</tbody>
</table>