Lattice Grid Buy a licence

demo D92

Undo and redo

A history stack over edits, fills and pastes

grid.history

Building…
Loading a live grid…

The configuration

import * as ng from '@angular/core';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import createLatticeGrid from '@toclocoinc/lattice-grid/modules/angular';

const { LatticeGridComponent } = createLatticeGrid({ ng, createGrid });

// One history stack over every kind of write: a typed cell, a fill, a paste
// and a range clear each land as one entry, so undo reverses the gesture
// rather than the cells it happened to touch. undoDepth sets how far back it
// reaches. The undo and redo buttons on the rail, and ctrl-z and ctrl-shift-z,
// both walk the same stack.
const columns = [
  { field: 'id', title: 'Order', layout: { width: 120, pin: 'start' } },
  { field: 'reference', title: 'Reference', layout: { width: 130 } },
  { field: 'team', title: 'Team', filter: { type: 'set' }, edit: true },
  // A real dropdown: the stage is picked from a fixed list rather than typed,
  // so the value is always one the grid knows about.
  { field: 'stage', title: 'Stage', filter: { type: 'set' },
    lookup: { options: [
      { id: 'planned', label: 'Planned' },
      { id: 'approved', label: 'Approved' },
      { id: 'in-flight', label: 'In-flight' },
      { id: 'blocked', label: 'Blocked' },
      { id: 'done', label: 'Done' },
    ] },
    edit: { enabled: true, editor: 'select', props: { allowClear: true } } },
  { field: 'due', title: 'Due', type: 'date', layout: { width: 140 }, edit: true },
  { field: 'circuits', title: 'Circuits', type: 'number', layout: { width: 110 }, edit: true },
  { field: 'impact', title: 'Impact', type: 'number', layout: { width: 100 }, edit: true },
  { field: 'effort', title: 'Effort', type: 'number', layout: { width: 100 }, edit: true },
  { field: 'budget', title: 'Budget', type: 'number', layout: { width: 140 },
    format: { style: 'currency', currency: 'GBP' }, total: 'sum', edit: true },
  { field: 'notes', title: 'Notes', layout: { flex: 1, min: 220 }, edit: { enabled: true, editor: 'textarea' } },
];

const rows = [/* work orders */];



@Component({
  selector: 'app-root',
  standalone: true,
  imports: [LatticeGridComponent],
  template: '<lattice-grid [config]="grid" style="display:block;height:540px"></lattice-grid>',
})
export class AppComponent {
  grid = {
    rowKey: 'id',
    selection: { mode: 'multiple', ranges: true },
    edit: { enabled: true, undoDepth: 100 },
    toolPanel: { side: 'left', panels: ['columns'], actions: ['undo', 'redo', 'restore'], exportName: 'work-orders' },
    columns: columns,
    rows: rows,
  };
}

bootstrapApplication(AppComponent);

Reversing edits with a grid-level history stack

Undo and redo give a user a way back out of a mistaken edit, fill, or paste without reloading data or hand-correcting cells. A developer reaches for this wherever the grid accepts direct manipulation rather than a form: inline editing, drag-fill, range paste, or a bulk edit. Lattice Grid tracks these mutations through grid.history, which records each committed change as a single entry regardless of how many cells it touched, so a paste covering four hundred cells undoes in one step rather than four hundred. The stack groups by transaction rather than by keystroke, which matters for a JavaScript data grid used for data entry: a user editing one cell across several keypresses gets one undo step for the commit, not one per character. Entries store the affected range and prior values rather than a full grid snapshot, so undoing a change on a hundred-thousand-row dataset costs the same as undoing one on a hundred-row dataset, and the operation replays through the same validation and change-detection path as a live edit, so a reverted cell re-triggers any dependent formula recalculation or row-level validation exactly as the original edit did. Keyboard handling follows platform convention, with Ctrl+Z and Ctrl+Shift+Z (or Cmd on macOS) wired to the stack by default and available as direct calls for a custom toolbar.

How do I add undo and redo to a JavaScript data grid?

Use grid.history, which maintains a stack of committed edits, fills, and pastes and exposes undo() and redo() alongside the default Ctrl+Z / Ctrl+Shift+Z bindings. Each stack entry represents one transaction, so a multi-cell paste or bulk edit reverses in a single step rather than one call per affected cell.