Lattice Grid Buy a licence

demo D70

Totals of the view or the data in Angular

The same grid filtered, totals answering each question in turn

totalFilteredOnly: false

This grid shows a total answering two different questions in turn: what the filtered rows in front of you add up to, and what the whole dataset adds up to. It makes clear which sum a footer is reporting, so a figure never quietly means the wrong thing.

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, 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';

const columns = [
  { field: 'account', title: 'Account', filter: { type: 'set' }, group: { enabled: true, index: 0 } },
  { field: 'service', title: 'Service', filter: { type: 'set' } },
  { field: 'resource', title: 'Resource', layout: { flex: 1, min: 200, max: 320 } },
  { field: 'environment', title: 'Env', filter: { type: 'set' },
    cell: { decoration: 'pill', variant: { map: {
      prod: 'danger', 'prod-2': 'danger', 'definitely-prod': 'danger',
      staging: 'warning', untagged: 'warning', test: 'info',
      dev: 'success', 'not-prod': 'neutral',
    } } } },
  { field: 'cost', title: 'Monthly cost', type: 'number', layout: { width: 170 },
    format: { style: 'currency', currency: 'USD', decimals: 2 }, total: 'sum' },
];

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [LatticeGridComponent],
  template: '<lattice-grid [config]="grid" (grid-ready)="onGridReady()" style="display:block;height:540px"></lattice-grid>',
})
export class AppComponent {
  @ViewChild(LatticeGridComponent) gridRef!: LatticeGridComponent;

  grid = {
    rowKey: 'id',
    totalFilteredOnly: true,
    grandTotalRow: 'bottom',
    toolPanel: { side: 'left', panels: ['columns', 'filters', 'views', 'quick'],
      actions: ['undo', 'redo', 'export', 'restore', 'maximise'], exportName: 'lattice-demo' },
    columns,
    rows: [/* cloud cost rows, one object per resource */],
  };

  // The grid is created once the view has rendered, so the live instance
  // arrives on grid-ready rather than in ngAfterViewInit.
  onGridReady() {
    const grid = this.gridRef.grid;
    // Narrow to production, then switch the totals between the view and the data.
    // true is the answer to "what am I looking at"; false is the answer to "what
    // is there", and says the filter is a lens rather than a selection. Both the
    // grand total and every group total follow the setting.
    const production = { col: 'environment', op: 'in', value: ['prod', 'prod-2', 'definitely-prod'] };
    grid.filters.set(production);
    grid.set('totalFilteredOnly', false);
    // Setting the same filter again is what drops the cached totals.
    grid.filters.set(production);
  }
}

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

Choosing whether a total reflects the filtered view or the full dataset

A grand total or group footer can answer two different questions, and a JavaScript data grid has to let a developer pick which one before the figure means anything. “What do the rows in front of the user add up to” is a different sum from “what do all the rows add up to, including the ones a filter is currently hiding”, and reports built on the wrong one erode trust quickly. Lattice Grid exposes the choice as totalFilteredOnly, a boolean read alongside the aggregation itself: set it false and a total keeps summing every row in the dataset regardless of the active filter, set it true and the same total narrows to only the rows currently matching. Because the setting sits next to the reducer rather than forcing a second query or a manual recompute, switching between the two views does not touch the underlying data or trigger a reload. A finance screen showing “total spend across the account” alongside “total spend in the current filter” can display both figures from the one dataset, each wired to its own totalFilteredOnly value, with the difference between them visible to the user as the filter changes.

Should a grid’s grand total include filtered-out rows?

It depends on what the total is meant to represent. Set totalFilteredOnly: false when the figure should stay anchored to the whole dataset, such as a running account balance. Set it true when the figure should track only what the user can currently see, such as “total of the rows matching this search”. Lattice Grid supports both from the same column definition.