History tracker
The History tracker in JSS automatically logs all changes made to the sheet. So, the user can undo (CTRL+Z) their actions and restore the sheet to a previous state or redo (CTRL+Y) their changes. This feature provides valuable safety for users, allowing them to restore changes and prevent losing their work.
If you are migrating from previous versions The new JSS version 10 significantly improves the history of changes. The change tracker is now decoupled from a specific grid instance and will track changes across all sheets on the screen. The new feature aligns the changes-tracking capabilities with other spreadsheet applications, allowing for safer cross-worksheet operations and providing a more comprehensive history of changes made to the worksheets available on the screen.
Documentation
Methods
The undo and redo methods are normally invoked by the CTRL+Z, CTRL+Y keyboard shortcut. The following methods can be called programmatically, as follows:
Method | Description |
---|---|
history.undo() | Undo the last spreadsheet changes.jspreadsheet.history.undo() : void |
history.redo() | Redo the most recent spreadsheet changes.jspreadsheet.history.redo() : void |
history.reset() | Remove all history entries.jspreadsheet.history.reset() : void |
Advance usage | |
history(object) | Add a new entry on the history tracker.jspreadsheet.history(changes: Object) : void |
Events
Events related to the history changes tracker.
Event | Description |
---|---|
onredo | onredo(worksheet: Object, info: Object) : null The info array contains all necessary information about the history and depends on which change was performed. |
onundo | onundo(worksheet: Object, info: Object) : null The info array contains all necessary information about the history and depends on which change was performed. |
Interface
The history tracker interface is composed of the following attributes:
Event | Description |
---|---|
index: number; | History index cursor |
actions: []; | History items |
cascade: boolean; | When true the next item is cascaded in the same existing history element |
ignore: boolean; | When true no history will be added to the tracker |
progress: string; | Tell if a history process is ongoing. |
undo: () => void; | Undo last action |
redo: () => void; | Redo most recent action |
reset: () => void; | Reset history tracker |
Examples
Controlling the changes programmatically
As explained above, the history actions are available on the spreadsheet level.
<html>
<script src="https://jspreadsheet.com/v10/jspreadsheet.js"></script>
<script src="https://jsuites.net/v5/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v10/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://jsuites.net/v5/jsuites.css" type="text/css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
<div id='spreadsheet'></div>
<br/>
<input type="button" value="Undo" id="undobtn" />
<input type="button" value="Redo" id="redobtn" />
<input type="button" value="Reset" id="resetbtn" />
<script>
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjhiOWZiZTZlMTRlMjY3NDdhMDY3NDE3ZmJlMTEyMzY5YWY3NjgxNDcxYTIxMjM3NzdiOWZlMzNlM2MzYzQyMmE3NjJlOWJlYzk5N2UwN2ZkZGYzNGJhMGJiMDU4YjcxMDk2MzE0MGU0NTY4ZmEyMTBjNTUzNWUyZThiNjUwMjcsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTBNalk0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==');
// Create the spreadsheet
let spreadsheet = jspreadsheet(document.getElementById('spreadsheet'), {
worksheets: [{
minDimensions: [8, 8],
}],
});
document.getElementById("undobtn").onclick = () => jspreadsheet.history.undo()
document.getElementById("redobtn").onclick = () => jspreadsheet.history.redo()
document.getElementById("resetbtn").onclick = () => jspreadsheet.history.reset()
</script>
</html>
import React, { useRef } from "react";
import { Spreadsheet, Worksheet } from "@jspreadsheet/react";
import jspreadsheet from "jspreadsheet";
const license = 'YjhiOWZiZTZlMTRlMjY3NDdhMDY3NDE3ZmJlMTEyMzY5YWY3NjgxNDcxYTIxMjM3NzdiOWZlMzNlM2MzYzQyMmE3NjJlOWJlYzk5N2UwN2ZkZGYzNGJhMGJiMDU4YjcxMDk2MzE0MGU0NTY4ZmEyMTBjNTUzNWUyZThiNjUwMjcsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTBNalk0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==';
export default function App() {
// Spreadsheet array of worksheets
const spreadsheet = useRef();
// Render component
return (
<>
<Spreadsheet ref={spreadsheet} license={license}>
<Worksheet minDimensions={[8,8]} />
</Spreadsheet>
<input type="button" value="Undo" onClick={() => jspreadsheet.history.undo()} />
<input type="button" value="Redo" onClick={() => jspreadsheet.history.redo()} />
<input type="button" value="Reset" onClick={() => jspreadsheet.history.reset()} />
</>
);
}
<template>
<Spreadsheet ref="spreadsheet" :license="license">
<Worksheet :minDimensions="[8,8]" />
</Spreadsheet>
<input type="button" value="Undo" @click="jspreadsheet.history.undo()" />
<input type="button" value="Redo" @click="jspreadsheet.history.redo()" />
<input type="button" value="Reset" @click="jspreadsheet.history.reset()" />
</template>
<script>
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/vue";
const license = 'YjhiOWZiZTZlMTRlMjY3NDdhMDY3NDE3ZmJlMTEyMzY5YWY3NjgxNDcxYTIxMjM3NzdiOWZlMzNlM2MzYzQyMmE3NjJlOWJlYzk5N2UwN2ZkZGYzNGJhMGJiMDU4YjcxMDk2MzE0MGU0NTY4ZmEyMTBjNTUzNWUyZThiNjUwMjcsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTBNalk0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==';
export default {
components: {
Spreadsheet,
Worksheet,
},
data() {
return {
license,
jspreadsheet,
}
}
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
import "jspreadsheet/dist/jspreadsheet.css"
import "jsuites/dist/jsuites.css"
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjhiOWZiZTZlMTRlMjY3NDdhMDY3NDE3ZmJlMTEyMzY5YWY3NjgxNDcxYTIxMjM3NzdiOWZlMzNlM2MzYzQyMmE3NjJlOWJlYzk5N2UwN2ZkZGYzNGJhMGJiMDU4YjcxMDk2MzE0MGU0NTY4ZmEyMTBjNTUzNWUyZThiNjUwMjcsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTBNalk0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==');
// Create component
@Component({
selector: "app-root",
template: `<div #spreadsheet></div>
<input type="button" value="Undo" (click)="jspreadsheet.history.undo()" />
<input type="button" value="Redo" (click)="jspreadsheet.history.redo()" />
<input type="button" value="Reset" (click)="jspreadsheet.history.reset()" />`,
})
export class AppComponent {
@ViewChild("spreadsheet") spreadsheet: ElementRef;
// Worksheets
worksheets: jspreadsheet.worksheetInstance[];
// Create a new data grid
ngAfterViewInit() {
// Create spreadsheet
this.worksheets = jspreadsheet(this.spreadsheet.nativeElement, {
worksheets: [{
minDimensions: [8, 8],
}],
});
}
}
Releases notes
Differences from version 9
As previously mentioned, the history tracker in JSS version 10 can register changes across all spreadsheets on the screen, regardless of the worksheet instance. Therefore, the syntax to access this feature need revision to the following:
Attribute | Description |
---|---|
worksheet.resetHistory() | Please use jspreadsheet.history.reset() |
worksheet.setHistory() | Please use jspreadsheet.history() |