Lattice Grid Buy a licence

demo D104

Row identity

Why rowKey matters, and the features that switch off without it

rowKey

Building…
Loading a live grid…

The configuration

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.js"></script>

<div id="grid" style="height: 540px"></div>

<script>
  // rowKey names the field that identifies a row. With it, an update carrying
  // an id matches its row wherever the row has scrolled or sorted to. Without
  // it the grid identifies rows by object identity and names them #0, #1, so an
  // update carrying an id matches nothing and comes back rejected as unknown-id.
  const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
    rowKey: 'id',
    selection: 'multiple',
    toolPanel: {
      side: 'left',
      panels: ['columns', 'filters', 'views', 'quick'],
      actions: ['undo', 'redo', 'export', 'restore', 'maximise'],
      exportName: 'lattice-demo',
    },
    statusBar: { panels: ['rowCount', 'progress', 'updates', 'selectedCount'] },
    highlightOnChange: { duration: 600 },
    columns: [
      { field: 'symbol', title: 'Symbol', layout: { width: 130, pin: 'start' } },
      { field: 'name', title: 'Instrument', layout: { flex: 1, min: 170, max: 280 } },
      { field: 'desk', title: 'Desk', filter: { type: 'set' } },
      { field: 'region', title: 'Region', filter: { type: 'set' } },
      { field: 'price', title: 'Price', type: 'number', layout: { width: 120 },
        format: { decimals: 4 }, filter: { type: 'number' } },
      { field: 'change', title: 'Change', type: 'number', layout: { width: 110 },
        format: { style: 'percent', decimals: 2 } },
      { field: 'ticks', title: 'Ticks', type: 'number', layout: { width: 90 } },
      { field: 'volume', title: 'Volume', type: 'number', layout: { width: 120 },
        format: { notation: 'compact' }, filter: { type: 'number' } },
      { field: 'status', title: 'Status', filter: { type: 'set' }, layout: { width: 110 },
        cell: { decoration: 'pill', variant: { map: { open: 'success', halted: 'danger', settled: 'neutral' } } } },
    ],
    rows,  // 5,000 instruments, each with an id
  });

  // Matched by key, so updates land whatever the current sort and filter.
  const result = grid.rows.apply({ update: [{ id: 'INS-0000042', price: 123.45 }] });
  console.log(result.updated.length, result.rejected);
</script>

Giving every row a stable key, and what breaks without one

Row identity is the link between a row’s data and the DOM node and internal state that represent it, and Lattice Grid establishes that link through rowKey, a function or field name that returns a stable value for a given row regardless of its position in the array. A developer sets it the moment rows can change independently of a full reload: a transaction updating a single field, a sort reordering the array, a streaming feed appending rows underneath ones already rendered. Without rowKey, a JavaScript data grid falls back to array index as identity, which is fine for a static dataset but wrong the instant a row moves, and selection, expanded detail panes and edit-in-progress state end up attached to whichever row now occupies that index rather than the row the user picked. With rowKey set, an update to row data reuses the existing DOM node and reapplies only the changed cells, instead of rebuilding the row, which is what keeps a resort or a batch of transactions from resetting scroll position or dropping focus mid-edit. It also lets the grid diff an incoming array against the one it already holds, so a merge of updated rows only touches the rows whose values actually changed.

What happens if I do not set rowKey on my data grid?

Lattice Grid falls back to using each row’s array index as its identity. Selection, expanded rows and in-progress edits then stay attached to a row position rather than a row’s actual data, so a sort, a filter, or an update that reorders the array can leave the wrong row selected or expanded, and incremental updates repaint by position instead of by row.