Aller au contenu

Angular

@dzgrid/angular enveloppe la grille DOM dans un composant autonome <dz-grid> aux entrées en signaux, pour Angular 19 à 22, sans zone d’abord (zone.js marche aussi). Quand la même chose se fait sans Angular, les onglets la montrent en TypeScript et avec le composant web.

Fenêtre de terminal
npm install @dzgrid/core @dzgrid/dom @dzgrid/theme @dzgrid/angular

Dans angular.json, chargez le thème avant vos propres styles globaux :

"styles": ["node_modules/@dzgrid/theme/dzgrid.css", "src/styles.css"]

L’hôte <dz-grid> est en display: contents (il n’a pas de boîte à lui) : dimensionnez son parent, en CSS global — les styles émulés d’un composant n’atteignent pas le DOM de la grille.

.grid-box { block-size: 480px; display: flex; flex-direction: column; }
.grid-box > dz-grid > .dzg { flex: 1; }
import { createGrid } from '@dzgrid/dom';
import type { ColumnOrGroup } from '@dzgrid/core';
import { FR } from '@dzgrid/dom/locales/fr';
type Comet = { id: string; name: string; seen: string; period: number };
const columns: ColumnOrGroup<Comet>[] = [
{ id: 'name', header: 'Comète', flex: 2 },
{ id: 'seen', header: 'Dernier passage', type: 'day', width: 140 },
{ id: 'period', header: 'Période (ans)', type: 'number', numberFormat: { maximumFractionDigits: 1 } },
];
createGrid<Comet>(document.querySelector<HTMLElement>('.grid-box')!, {
rows: [
{ id: 'c1', name: 'Vantor-Orme', seen: '2024-08-19', period: 71.4 },
{ id: 'c2', name: 'Ossian Bleue', seen: '2025-01-03', period: 6.2 },
],
columns,
getRowId: (c) => c.id,
messages: FR,
locale: 'fr-FR',
label: 'Comètes',
});

Dessinée sur cette page par @dzgrid/dom, la grille qu’enveloppe <dz-grid>.

columns, getRowId et messages sont obligatoires (messages peut venir de provideDzGrid, plus bas). Typez le tableau de colonnes DzgColumnOrGroup<T>[] : un littéral non typé cache les clés inconnues.

Les entrées sont des signaux. Donnez un nouveau tableau ou objet pour changer quelque chose (rows.update((rs) => [...rs, x])), jamais un objet modifié. Gardez les fonctions (getRowId, rowClass) et le tableau features en champs de la classe : features est lu une fois, à la création de la grille.

import { createGrid } from '@dzgrid/dom';
import { filters } from '@dzgrid/dom/filters-base';
import { FR } from '@dzgrid/dom/locales/fr';
import { FR_FILTERS } from '@dzgrid/dom/locales/fr-filters';
type Lamp = { id: number; model: string; watts: number };
let rows: Lamp[] = [{ id: 1, model: 'Phalène 3', watts: 40 }];
const grid = createGrid<Lamp>(document.getElementById('lamps')!, {
rows,
columns: [{ id: 'model', header: 'Modèle' }, { id: 'watts', header: 'Watts', type: 'number' }],
getRowId: (l) => l.id,
messages: { ...FR, text: { ...FR.text, ...FR_FILTERS.text } },
features: [filters()],
selection: { mode: 'multi', checkbox: true },
onEvent: (e) => {
if (e.type === 'selectionChanged') console.log(e.count ?? 'quelques', 'sélectionnées');
},
});
// Un nouveau tableau, jamais l’ancien modifié.
rows = [...rows, { id: rows.length + 1, model: 'Héron 1', watts: 25 }];
grid.update({ rows });

Modèles à double sens : [(quick)], [(filter)], [(selected)], [(expanded)], [(groupBy)]. Non liés, c’est la grille qui tient cet état.

provideDzGrid donne à chaque <dz-grid> de l’application ses textes et ses réglages par défaut. Une liaison sur la balise l’emporte sur une valeur par défaut.

import { ApplicationConfig } from '@angular/core';
import { provideDzGrid } from '@dzgrid/angular';
import { FR } from '@dzgrid/dom/locales/fr';
export const appConfig: ApplicationConfig = {
providers: [provideDzGrid({ messages: FR, defaults: { locale: 'fr-FR', timeZone: 'Europe/Paris', density: 'compact' } })],
};

(gridReady) remet un DzgController : commandes, focus, transactions, et l’api propre à chaque fonction par use. Sans Angular, la grille elle-même offre la même chose : grid.kernel et grid.api.

import { createGrid } from '@dzgrid/dom';
import { dataKey } from '@dzgrid/core';
import { FR } from '@dzgrid/dom/locales/fr';
type Owl = { id: string; name: string; age: number };
const grid = createGrid<Owl>(document.getElementById('owls')!, {
rows: [{ id: 'o1', name: 'Pépin', age: 3 }, { id: 'o2', name: 'Ronce', age: 9 }],
columns: [{ id: 'name', header: 'Chouette' }, { id: 'age', header: 'Âge', type: 'number' }],
getRowId: (o) => o.id,
messages: FR,
selection: { mode: 'multi' },
});
grid.kernel.dispatch({ type: 'sort.set', sort: [{ column: 'age', dir: 'desc' }] }, 'api');
const key = dataKey('o2');
if (key) {
grid.api.ensureVisible(key, 'name');
grid.kernel.dispatch({ type: 'selection.only', row: key }, 'api');
}
grid.kernel.rows.applyTransaction({ patch: [{ id: 'o1', set: { age: 4 } }] });

Une cellule (ou un en-tête, une infobulle, un éditeur, un panneau de détail…) peut être un composant Angular avec une entrée signal nommée cell. Les instances sont réutilisées d’une ligne à l’autre : tirez tout de cell().

import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import { DzGrid, type DzgColumnOrGroup, type DzgPartContext } from '@dzgrid/angular';
import { FR } from '@dzgrid/dom/locales/fr';
type Robot = { id: string; name: string; state: 'awake' | 'asleep' };
@Component({
selector: 'app-robot-state',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<span>{{ cell().text }}</span>
<button type="button" (click)="cell().emit('wake', robot().id)">Réveiller</button>`,
})
export class RobotState {
readonly cell = input.required<DzgPartContext<'cell'>>();
robot(): Robot { return this.cell().row as Robot; }
}
@Component({
selector: 'app-robots',
imports: [DzGrid],
template: `<dz-grid [rows]="rows" [columns]="columns" [getRowId]="rowId" [messages]="messages"
(cellAction)="last = $event.name + ' ' + $event.detail" />`,
})
export class Robots {
readonly rows: Robot[] = [{ id: 'r1', name: 'Tic', state: 'asleep' }];
readonly columns: DzgColumnOrGroup<Robot>[] = [{ id: 'name', header: 'Robot' }, { id: 'state', header: 'État', ui: { cell: RobotState } }];
readonly rowId = (r: Robot) => r.id;
readonly messages = FR;
last = '';
}

Autres façons de donner une partie : componentPart(slot, Component) dans [parts] ou provideDzGrid({ parts }) ; un <ng-template dzgPart="name" [slot]="'header'" let-c> dans <dz-grid> (importez DzgPart) ; ou une partie DOM simple faite avec definePart de @dzgrid/dom.

  • La page TypeScript, pour ce que fait la grille sous le composant.
  • Les guides, tâche par tâche, en commençant par les colonnes.