Lattice Grid Buy a licence

demo D227

Cross-filtering, the path back up

Two summary panels over one book; click a row in either and it filters the book, so the other narrows

crossFilter: true · crossFilter.toggle

Building…
Loading a live grid…

The configuration

import * as ng from '@angular/core';
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import createLatticeGrid from '@toclocoinc/lattice-grid/modules/angular';

const { LatticeGridComponent } = createLatticeGrid({ ng, createGrid });

const USD = { style: 'currency', currency: 'USD', maximumFractionDigits: 0 };
const bookColumns = [
  { field: 'rep', title: 'Rep' },
  { field: 'region', title: 'Region' },
  { field: 'amount', title: 'Deal', type: 'number', format: USD, total: 'sum' },
];
const regionColumns = [
  { field: 'region', title: 'Region' },
  { field: 'revenue', title: 'Revenue', type: 'number', format: USD },
];
const repColumns = [
  { field: 'rep', title: 'Rep' },
  { field: 'revenue', title: 'Revenue', type: 'number', format: USD },
];

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, LatticeGridComponent],
  template:
    '<lattice-grid #book [config]="bookGrid" style="display:block;height:300px"></lattice-grid>' +
    '<div style="display:flex;gap:16px;margin-top:16px">' +
    '  <lattice-grid #regionGrid *ngIf="byRegion" [config]="byRegion" (ready)="wire(regionGrid)" style="flex:1"></lattice-grid>' +
    '  <lattice-grid #repGrid *ngIf="byRep" [config]="byRep" (ready)="wire(repGrid)" style="flex:1"></lattice-grid>' +
    '</div>',
})
export class AppComponent implements AfterViewInit {
  @ViewChild('book') bookRef!: LatticeGridComponent;
  byRegion: any = null;
  byRep: any = null;

  bookGrid = { rowKey: 'id', toolPanel: { side: 'left', panels: ['filters', 'columns'] }, columns: bookColumns, rows: [/* e.g. { id: 'S0', rep: 'Ana', region: 'EMEA', amount: 1830 } */] };

  // Each summary panel derives from the live book and follows its filter.
  // crossFilter: true lets a panel push the clicked group onto the book as an
  // ordinary filter, so the other panel re-derives and both narrow each other
  // while staying whole.
  ngAfterViewInit() {
    const book = this.bookRef.grid;
    const panel = (col: string) => ({ autoHeight: true, columns: col === 'region' ? regionColumns : repColumns, source: { mode: 'derived', from: book, follow: 'filtered', refresh: 'live', groupBy: col, crossFilter: true,
      select: { revenue: { of: 'amount', fn: 'sum' }, deals: { fn: 'count' } }, sort: [{ col: 'revenue', dir: 'desc' }] } });
    this.byRegion = panel('region');
    this.byRep = panel('rep');
  }

  // A click on a panel row toggles that group as the book's filter.
  wire(cmp: LatticeGridComponent) {
    const g = cmp && cmp.grid;
    if (g) g.on('row:click', (e: any) => g.crossFilter.toggle(e.key));
  }
}

bootstrapApplication(AppComponent);