Lattice Grid Buy a licence

developer guide

Coming from Handsontable

A concept-to-concept map from a Handsontable grid to Lattice Grid, one before-and-after setup, and a straight answer on the one thing that does not carry across.

How your grid maps across

Most of a Handsontable setup has a direct equivalent here, and the names are close enough that the move reads as a rename rather than a rewrite. You keep your data as objects, keep your columns, keep your editors and validators, and keep the hook that saves a change. The table below is the whole map for the common surface.

In Handsontable In Lattice Grid
data (array of objects) rows, with rowKey naming the stable id column
columns and colHeaders columns, each with a field and a title
type: numeric, date, checkbox, dropdown type: number, date, boolean, lookup, plus a library of technical types for units, network, time and more
numericFormat and dateFormat format on the column, using the platform number and date formatter
renderer the cell renderer options: pills, dots, bars and in-cell charts, or a function for full control
afterChange the cell:changed event, and edit.commit for a write that persists and rolls back on rejection
validator validation on the column: the edit is refused and the reason shown before it is written
filters and dropdownMenu a per-column filter, including filter: { type: 'set' } for a checkbox list, a condition tree, and a quick filter across the whole grid
columnSorting and multiColumnSorting single and multi-column sort, on by default
nestedHeaders column groups with grouped, movable headers
grouping rows by a value row grouping with subtotals and a pivot, each group a total the grid computes
manualColumnResize, manualColumnMove, manualRowMove column resize, column reorder and row reorder, on by default
fixedColumnsStart and fixedRowsTop pinned columns and pinned rows, set on the column or the layout
hiddenColumns column visibility and a tool panel that shows, hides and reorders columns
mergeCells cell, row and column spanning
copy, paste and the fill handle clipboard interop with Excel and Sheets, cell ranges, and the fill handle
undoRedo undo and redo across the whole grid
contextMenu a built-in context menu you can extend with your own items
the CSV export plugin Excel and CSV export built in, with no plugin and no dependency
a formula typed into a cell a formula that names columns rather than cell addresses, evaluated when it is committed, with computed columns for a value that must stay in step

Before and after

The same three-column grid, editable and filterable, with a save on every change. First in Handsontable, then in Lattice Grid.

Handsontable

import Handsontable from 'handsontable';
import 'handsontable/dist/handsontable.full.css';

new Handsontable(el, {
  data: rows,
  colHeaders: ['Circuit', 'Region', 'Monthly charge'],
  columns: [
    { data: 'circuit' },
    { data: 'region' },
    { data: 'charge', type: 'numeric', numericFormat: { pattern: '$0,0.00' } },
  ],
  columnSorting: true,
  filters: true,
  dropdownMenu: true,
  afterChange(changes, source) {
    if (source === 'edit') save(changes);
  },
  licenseKey: 'non-commercial-and-evaluation',
});

Lattice Grid

import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';

const grid = createGrid(el, {
  rowKey: 'id',
  columns: [
    { field: 'circuit', title: 'Circuit' },
    { field: 'region', title: 'Region', filter: { type: 'set' } },
    { field: 'charge', title: 'Monthly charge', type: 'number',
      format: { style: 'currency', currency: 'USD' }, total: 'sum' },
  ],
  rows,
  edit: { enabled: true, commit: (change) => save(change) },
});

// The write already happened on screen; commit persists it and rolls back
// on a rejection. The cell:changed event reports every accepted edit.
grid.on('cell:changed', (e) => console.log(e.field, e.value));

The shape is the same: your rows, your columns, an editor, a filter and a save. Formatting moves onto the column as format, the set filter replaces the dropdown menu, and the save is an edit that applies on screen at once and asks your server to confirm, rolling the cell back to its last confirmed value if the write is refused.

What our formulas do, and where they stop

Check this against your sheet before you plan the move, because it is the one place where a workbook can fail to survive it.

What carries across: a user types = into a cell and gets a real formula. =quantity * unitPrice, =ROUND(quantity * unitPrice, 2), =IF(quantity > 10, "bulk", "single"), =MAX(readings) - MIN(readings), and functions of your own registered beside the built-in ones. References name columns rather than cell addresses, so a formula means the same thing after the grid is sorted, filtered, grouped or paged, and it is parsed rather than run, so text a user typed never reaches the JavaScript engine. A formula commits as one undo step and goes through the column's validation like any other value.

Where it stops: a typed formula is evaluated once, at the moment it is committed, and what lands in the cell is a value. It does not re-evaluate when a cell it referred to changes later. For a value that must stay in step with its inputs, declare a computed column and the grid keeps it current as its dependencies move. So a sheet whose point is a chain of cells recalculating each other is the part to plan for; a column that is those two multiplied moves over as it is.

For pricing, licensing and a live grid to click through, see the Handsontable comparison. To start building, the developer guide and the editing guide cover the rest.