demo D283
Validation declared on the column in Angular
An invalid edit vetoed with an announced inline error, from rules stated as data
validation: { required, min, max, pattern, oneOf }
This grid states its edit rules as data on the column, required, min, max, a pattern or an allowed list, and vetoes an invalid edit with an announced inline error. It keeps the definition of a good value next to the column, so validation is readable and consistent rather than hand-coded per field.
This is the Angular version. A standalone component takes the whole configuration through one config input, surfaces grid events as outputs, and exposes the live grid on a getter for anything the inputs do not cover.
The configuration
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import { LatticeGridComponent, provideLattice } from '@toclocoinc/lattice-grid/angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [LatticeGridComponent],
template: '<lattice-grid [config]="grid" style="display:block;height:520px"></lattice-grid>',
})
export class AppComponent {
grid = {
rowKey: 'id',
selection: 'multiple',
edit: true,
columns: [
{ field: 'id', title: 'Order', layout: { width: 120, pin: 'start' } },
{ field: 'reference', title: 'Reference', layout: { width: 130 }, edit: true,
validation: {
required: true,
pattern: '^(CHG|INC|REQ)-\\d{4}$',
messages: { pattern: 'Use CHG, INC or REQ followed by four digits.', required: 'A reference is required.' },
} },
{ field: 'team', title: 'Team', filter: { type: 'set' }, edit: true,
validation: { required: true, oneOf: ['Core', 'Platform', 'Edge', 'Field'], messages: { oneOf: 'Pick one of the four teams.' } } },
{ field: 'circuits', title: 'Circuits', type: 'number', layout: { width: 110 }, edit: true,
validation: { required: true, min: 1, max: 40, messages: { min: 'At least one circuit.', max: 'Forty circuits at most.' } } },
{ field: 'budget', title: 'Budget', type: 'number', layout: { width: 140 },
format: { style: 'currency', currency: 'GBP' }, total: 'sum', edit: true,
// A cross-field rule: the budget is read against the circuits on the
// same row, so the ceiling moves with the record.
validation: {
min: 0,
messages: { min: 'A budget cannot be negative.' },
crossField: (value: unknown, row: any) => {
const circuits = Number((row.data ?? row).circuits ?? 0);
return Number(value) <= circuits * 5000 ? true : 'At ' + circuits + ' circuits the cap is ' + (circuits * 5000);
},
} },
],
rows: [/* work orders: id, reference, team, circuits, budget */],
};
}
bootstrapApplication(AppComponent, {
providers: [provideLattice({ createGrid })],
});
Validation stated as data, enforced before the value lands
A grid that lets people edit needs to say what a good value looks like. Lattice Grid takes those rules as data on the column: validation accepts required, min and max, minLength and maxLength, a pattern, a oneOf list, and a crossField predicate for a rule that reads the rest of the row. Each rule is checked against a new value before it is written. A failing value is vetoed, so the cell keeps its old value and nothing half-valid ever lands, and the cell is marked with the grid’s own invalid state, an error that is announced to a screen reader rather than shown only as a red border. Correct the value and the mark clears.
Declaring the rules rather than writing them as a function keeps the constraints in one readable place, checkable outside the render path, and lets a rule carry its own message so a person sees “Use CHG, INC or REQ followed by four digits” instead of a generic refusal. Only a person’s edit is gated: a value written by your own code or arriving from a live feed is treated as the authority and lands untouched, so validation guards the keyboard without fighting your data flow.
How do I stop a grid accepting an invalid edit?
Declare the rules on the column under validation: required for a value that may not be blank, min and max for a number or date range, pattern for a shape the whole value must match, oneOf for a fixed set, and crossField for a rule that compares against other fields on the same row. A failing edit is vetoed before it is written, the cell is marked with an announced inline error, and a corrected value clears the mark. Give a rule its own message through messages so the reason is specific rather than generic.