Lattice Grid Buy a licence

developer guide

A List Column Type in a JavaScript Data Grid

Many values in one cell, each one still usable on its own: chips, a token editor, and filters that ask about the whole list.

The list column type

Import the list module and a column can be declared type: 'list', with typeOptions.of naming the type each item holds. A cell reads as chips rather than a joined string, so a reader sees every value and how many there are without opening the cell.

import '@toclocoinc/lattice-grid/modules/list';

const grid = createGrid(el, {
  columns: [
    { field: 'product', title: 'Product' },
    { field: 'channels', title: 'Channels', type: 'list', typeOptions: { of: 'text' } },
  ],
  rows,
});
// A cell holds an array of items of the given item type. It draws as chips
// with a "+N" overflow count and a tooltip listing every item, and edits
// with a token editor: Enter adds one, Backspace removes the last, and a
// pasted comma-separated string splits into several.

Filters that ask about the whole list

The ordinary filter row and a set filter's ticked values match a row where any item matches, so a many-valued column stays as filterable as a single-valued one with no extra configuration. Four further operators ask about the list as a whole.

grid.filters.set({ col: 'channels', op: 'eq', value: 'web' });        // matches a row where any item is 'web'
grid.filters.set({ col: 'channels', op: 'hasAll', value: ['web', 'wholesale'] });
grid.filters.set({ col: 'channels', op: 'hasAny', value: ['export'] });
grid.filters.set({ col: 'channels', op: 'hasNone', value: ['retail'] });
grid.filters.set({ col: 'channels', op: 'listCount', value: { gt: 2 } });

Sorting, grouping and export

A list column sorts by item count and then by its first item, groups by its joined text, and copies to the clipboard, CSV and Excel as its items joined by a comma (or a joiner you set in typeOptions). The AI layer's schema describes the column as a list of its item type, so a question about it reads correctly too.

Pushed into a DuckDB LIST column

Point the DuckDB adapter at a table or a Parquet file carrying a LIST column and every one of these operators runs inside the database instead of the browser.

const source = createPushdownSource({
  adapter: duckdbAdapter({ connection, from: "read_parquet('products.parquet')" }),
  compute,
  pageSize: 200,
});
// A LIST column pushes hasAny, hasAll, hasNone and listCount into DuckDB as
// list_has_any, list_contains and len(list_filter(...)), with typed bindings,
// so filtering a hundred thousand rows of tagged data runs in the engine.

See it running: chips, a token editor and hasAll filtering over a product catalogue. The data types guide covers every other column type, and the DuckDB adapter guide covers pushdown in full.