Remarks
By implementing this interface as well as ILookup, clients can add undoability for changes to their model classes. The yFiles undo mechanism uses the return value of getState to retrieve a state of an item at the beginning of the compound editing process. When the process ends, another state will be retrieved of the same item and compared to the original state. If they differ, an IUndoUnit is created that uses the applyState method to apply either state to the item in case of undo or redo. This represents an abstraction to the undo mechanism where it is only needed to define "states" of items and hides the more complicated mechanism of creating and inserting IUndoUnits.
The following is an example implementation of an item that is being managed using IMementoSupport:
class Employee extends BaseClass<ILookup>(ILookup) implements ILookup {
_name: string
position: string
age: number
constructor(name: string, position: string, age: number) {
super()
this._name = name
this.position = position
this.age = age
}
get name(): string {
return this._name
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
lookup<T extends any>(type: Constructor<any>): T | null {
if (type === IMementoSupport) {
return new EmployeeMementoSupport() as T
}
return null
}
}A collection of items from this type can then be watched using the following code snippet:
const edit = graph.beginEdit(
undoName,
redoName,
listWithMyEmployeesToWatch,
)
// changes to the employees are done here
if (!success) {
// if we don't want the changes to be done after all, then we need to cancel the edit
edit.cancel()
}Implementing the IMementoSupport interface is quite unrestrained, the type of the state returned by getState method can by anything as long as the applyState and stateEquals methods can deal with it:
class EmployeeMementoSupport
extends BaseClass<IMementoSupport>(IMementoSupport)
implements IMementoSupport
{
getState(subject: any): EmployeeState | null {
if (subject instanceof Employee) {
return new EmployeeState(subject.position, subject.age)
}
return null
}
applyState(subject: any, state: any): void {
if (subject instanceof Employee && state instanceof EmployeeState) {
subject.position = state.position
subject.age = state.age
}
}
stateEquals(state1: any, state2: any): boolean {
if (
state1 instanceof EmployeeState &&
state2 instanceof EmployeeState
) {
return (
state1.position === state2.position && state1.age === state2.age
)
}
return state1 === state2
}
}
class EmployeeState {
_position: string
_age: number
constructor(position: string, age: number) {
this._position = position
this._age = age
}
get position(): string {
return this._position
}
get age(): number {
return this._age
}
}In summary, use this concept when you want to track the state of items during certain operations for undo/redo. This is efficient if it's easier to handle an item's state than the changes to the item themselves. If you want to focus on the changes or on certain events, you should use custom IUndoUnit implementations instead.
See Also
Developer's Guide
API
- ILookup, ICompoundEdit, UndoEngine
Members
Methods
Parameters
- subject: any
- The subject to read the state from
Return Value
- any
- An object that describes the current state of
subject.
See Also
Developer's Guide
false, an IUndoUnit is created for the two states that can reapply either state (for either undo or redo). If this method returns true the state is considered not to have changed and no undo unit will be created. Conservative implementations may simply return false.Parameters
- state1: any
- The first state as obtained from getState
- state2: any
- The second state as obtained from getState
Return Value
- boolean
trueif the states are equal;falseotherwise.
See Also
Developer's Guide