Lattice Grid Buy a licence

angular data grid · filtering

Angular Grid: Filtering

A per-column filter menu with the operators each type supports, and an inline filter row that writes the exact same condition, so a reader who prefers typing under the header gets to, without a second filtering system underneath.

Also in: React

Install and import

npm install @toclocoinc/lattice-grid
# free on localhost; a production domain needs a licence key (see /pricing/)

The file

service-filtering.component.ts

// service-filtering.component.ts
import { Component, signal, viewChild } 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';

// columnDefaults turns the per-column filter menu on across the board; each
// column offers the operators that suit its own type.
const COLUMNS = [
  { field: 'service', title: 'Service', layout: { pin: 'start', width: 140 } },
  { field: 'team', title: 'Team', filter: { type: 'set' } },
  { field: 'owner', title: 'Owner', filter: { type: 'set' } },
  { field: 'tier', title: 'Tier', cell: { decoration: 'pill', variant: { map: { gold: 'warning', silver: 'neutral', bronze: 'info' } } } },
  { field: 'state', title: 'State', cell: { decoration: 'dot', variant: { map: { healthy: 'success', degraded: 'warning', failing: 'danger', unknown: 'neutral' } } } },
  { field: 'region', title: 'Region', filter: { type: 'set' } },
  { field: 'active', title: 'Active', type: 'boolean' },
  { field: 'deprecated', title: 'Deprecated', type: 'boolean' },
];

@Component({
  selector: 'app-service-filtering',
  standalone: true,
  imports: [LatticeGridComponent],
  template:
    '<div style="display:flex;align-items:center;gap:12px;margin-bottom:10px">' +
    '  <span>Filter row</span>' +
    '  <button type="button" [attr.aria-pressed]="!filterRow()" (click)="toggle(false)">Off</button>' +
    '  <button type="button" [attr.aria-pressed]="filterRow()" (click)="toggle(true)">On</button>' +
    '</div>' +
    '<lattice-grid #grid [config]="config" (grid-ready)="onReady($event)" style="display:block;height:460px"></lattice-grid>',
})
export class ServiceFilteringComponent {
  grid = viewChild<LatticeGridComponent>('grid');
  filterRow = signal(false);

  // filterRow starts off in the configuration; the buttons flip it live
  // through the instance (grid-ready) hands back, the same
  // grid.set('filterRow', …) a plain JavaScript page would call.
  config = {
    rowKey: 'id',
    filterRow: false,
    columnDefaults: { filter: true },
    toolPanel: { side: 'left', panels: ['filters', 'columns'], actions: ['restore'], exportName: 'lattice-demo' },
    columns: COLUMNS,
    rows: [] as unknown[], // service records
  };

  private instance: any = null;
  onReady(grid: any) { this.instance = grid; }

  toggle(on: boolean) {
    this.filterRow.set(on);
    this.instance?.set('filterRow', on);
  }
}

bootstrapApplication(ServiceFilteringComponent, {
  providers: [provideLattice({ createGrid })],
});

See it running

Building…
Loading a live grid…

Open this demo's Angular tab →

Working in Angular

The row is a config key, not a second filter store. Toggling filterRow through grid.set('filterRow', value) shows or hides the inline row; whatever a reader types there and whatever they pick from a column's menu land on the same condition tree.

(grid-ready) arrives before you would otherwise have an instance. It hands you the live grid the moment it exists, which is what the toggle button calls into, rather than reaching through the signal query on every click.

columnDefaults is mount-time. It sets the starting shape for every column that does not declare its own filter; give the component a new instance, or drive columns through the instance directly, for a full reconfiguration after mount.

Related