History Tracker
The Jspreadsheet History Tracker automatically records all modifications. So, Users can undo or redo actions with CTRL+Z and CTRL+Y, respectively.
If you are migrating from Version 9 or before
Starting with Version 10, JSS enhances change tracking by decoupling it from specific grid instances, allowing monitoring across all sheets. This upgrade aligns JSS with standard spreadsheet functionalities, supporting safer cross-worksheet activities and providing a detailed change history.
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
Method | Description |
---|---|
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/v11/jspreadsheet.js"></script>
<script src="https://jsuites.net/v5/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v11/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>
<p><input type="button" value="Undo" id="btn1" />
<input type="button" value="Redo" id="btn2" />
<input type="button" value="Reset" id="btn3" /></p>
<script>
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('MjkyNjJhNDdlNGIyNzRiZmYxZDFjMDYzNjkwYjY1YzkzNGM5NzFjZjI0NDkwNTZmZGMwYTNiOTE3NjE2N2I1NjExYzViNzZiZDNlMTQ2YzQxYmVmYjY3ZDUwZWJmZDliZDNiYWI5YTlkMWI2YjY0MWE3MWE1ODliMGE3YmQ0MzksZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTJNakU1TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==');
// Create the spreadsheet
let spreadsheet = jspreadsheet(document.getElementById('spreadsheet'), {
worksheets: [{
minDimensions: [6, 6],
}],
});
document.getElementById("btn1").onclick = () => jspreadsheet.history.undo()
document.getElementById("btn2").onclick = () => jspreadsheet.history.redo()
document.getElementById("btn3").onclick = () => jspreadsheet.history.reset()
</script>
</html>
import React, { useRef } from "react";
import { Spreadsheet, Worksheet } from "@jspreadsheet/react";
import jspreadsheet from "jspreadsheet";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
const license = 'MjkyNjJhNDdlNGIyNzRiZmYxZDFjMDYzNjkwYjY1YzkzNGM5NzFjZjI0NDkwNTZmZGMwYTNiOTE3NjE2N2I1NjExYzViNzZiZDNlMTQ2YzQxYmVmYjY3ZDUwZWJmZDliZDNiYWI5YTlkMWI2YjY0MWE3MWE1ODliMGE3YmQ0MzksZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTJNakU1TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==';
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";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
const license = 'MjkyNjJhNDdlNGIyNzRiZmYxZDFjMDYzNjkwYjY1YzkzNGM5NzFjZjI0NDkwNTZmZGMwYTNiOTE3NjE2N2I1NjExYzViNzZiZDNlMTQ2YzQxYmVmYjY3ZDUwZWJmZDliZDNiYWI5YTlkMWI2YjY0MWE3MWE1ODliMGE3YmQ0MzksZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTJNakU1TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==';
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('MjkyNjJhNDdlNGIyNzRiZmYxZDFjMDYzNjkwYjY1YzkzNGM5NzFjZjI0NDkwNTZmZGMwYTNiOTE3NjE2N2I1NjExYzViNzZiZDNlMTQ2YzQxYmVmYjY3ZDUwZWJmZDliZDNiYWI5YTlkMWI2YjY0MWE3MWE1ODliMGE3YmQ0MzksZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpNeU1qWTJNakU1TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0ozWldJaUxDSnNiMk5oYkdodmMzUWlYU3dpY0d4aGJpSTZJak0wSWl3aWMyTnZjR1VpT2xzaWRqY2lMQ0oyT0NJc0luWTVJaXdpZGpFd0lpd2lkakV4SWl3aVkyaGhjblJ6SWl3aVptOXliWE1pTENKbWIzSnRkV3hoSWl3aWNHRnljMlZ5SWl3aWNtVnVaR1Z5SWl3aVkyOXRiV1Z1ZEhNaUxDSnBiWEJ2Y25SbGNpSXNJbUpoY2lJc0luWmhiR2xrWVhScGIyNXpJaXdpYzJWaGNtTm9JaXdpY0hKcGJuUWlMQ0p6YUdWbGRITWlMQ0pqYkdsbGJuUWlMQ0p6WlhKMlpYSWlMQ0p6YUdGd1pYTWlYU3dpWkdWdGJ5STZkSEoxWlgwPQ==');
// Create component
@Component({
standalone: true,
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],
}],
});
}
}
Release Notes
As previously mentioned, from version 10 the history tracker 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() |