Lattice Grid Buy a licence

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.

Building…
Loading a live grid…

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.