Skip to main content

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:

todos.component.ts
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:

todos.component.html
<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>