developer guide
End-User Formatting Controls in a Data Grid
grid.formatting opens the same rule engine to the reader: they pick the column, the test and the look from a panel, see it applied at once, and keep it, because their rules travel in the saved view along with sort, filter and column order.
Developer guide › Columns and cell rendering › End-User Formatting Controls in a Data Grid
Formatting an end user can change
compileRules() above compiles at configuration time into cell.style,
which you write and a user cannot reach. grid.formatting holds the same rules as
runtime state instead: the cell layer asks it on every paint, so a rule added while the grid
is running takes effect on the next frame.
Rules as state
grid.formatting.add('margin', { when: { op: 'lt', value: 0 }, style: { background: '#fbeceb' } });
grid.formatting.add('*', { when: { op: 'blank' }, style: { background: '#f1f3f5' } });
grid.formatting.list('margin'); // [{ id, when, style }, …] in evaluation order
grid.formatting.move('margin', id, 0); // order decides which rule wins
grid.formatting.update('margin', id, { enabled: false });
grid.formatting.clear('margin');
Two scopes, one ordered list. A rule sits on a column id or on
'*' for every column. Evaluation joins them: grid-wide first, then the column's
own, so a column rule can override a grid-wide one, and stopIfTrue means the
same thing across the join as it does within either half.
Saved views and undo came free. The rules are a section of
GridState, and both saved views and the undo timeline are built on that. Nothing
in the formatting model knows either exists.
Rules must be JSON. style cannot be a function here, because
the rules are serialised into views and undo slices. Config-time cell.style still
takes one, which is the right home for a rule a user should not be able to change.
Both paths coexist. Where a column has a cell.style and a
runtime rule matches, the two are merged and written once; the runtime rule wins for the
properties it names and leaves the rest of your styling alone.
Group rows are not formatted. A group row summarises many values rather than being an instance of one, which is the same reason decoration is dropped for it.
The panel
createGrid(el, { toolPanel: { side: 'right', panels: ['columns', 'filters', 'formatting'] } });
The panel is a form over that array and nothing more: every control is one call into
grid.formatting, which is what makes each gesture undoable without the panel
knowing undo exists. It exposes ordering because ordering is meaning: dragging a rule up can
change which of two colours a cell takes.
Icon sets and data bars are column decorations
rather than cell styles, the bar and icon decorations already
render them, and driving those from the panel needs a runtime column-decoration API that
persists and undoes alongside the rules. Building it as a second bar implementation inside
the rule engine was the alternative, and the wrong one.