Aller au contenu

TypeScript

@dzgrid/dom dessine la grille dans n’importe quelle page, sans framework. @dzgrid/core fait les calculs (sans DOM) et @dzgrid/theme apporte le CSS. Cette page utilise createGrid directement ; les onglets montrent la même grille avec Angular et avec le composant web.

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

@dzgrid/dom/filters et @dzgrid/dom/editors chargent un calendrier de dates venu de @tzslot/core et @tzslot/dom : installez-les aussi si vous utilisez ces deux entrées. Sans eux, importez depuis @dzgrid/dom/filters-base et @dzgrid/dom/editors-base, qui n’ont pas de calendrier : avec filters-base, une colonne de jours ou d’instants n’a aucun filtre (pas de bouton) et un avertissement missing-feature ; avec editors-base, elle se modifie en tapant. Les filtres de jours viennent de @dzgrid/dom/filters (ou de filters-base muni de loadDates).

La grille remplit son élément hôte, quel que soit son nombre de lignes : donnez une hauteur à l’hôte.

<div id="books" style="block-size: 320px; display: flex; flex-direction: column"></div>

Avec 3 lignes ou 10 000, la grille a la hauteur de l’hôte, défile à l’intérieur et ne dessine que les lignes visibles. Une hauteur fixe, une part de flex ou de grid conviennent toutes ; la colonne flex laisse une barre se placer au-dessus de la grille. Un hôte sans hauteur (dimensionné par son contenu) fait grandir la grille avec ses lignes ; elle limite alors sa vue à la hauteur de la fenêtre et signale une fois un événement problems de code unbounded-viewport (chemin host).

import { createGrid } from '@dzgrid/dom';
import type { ColumnOrGroup } from '@dzgrid/core';
import { FR } from '@dzgrid/dom/locales/fr';
import '@dzgrid/theme/dzgrid.css';
type Book = { id: string; title: string; author: string; published: string; price: number };
const rows: Book[] = [
{ id: 'b1', title: 'Le Verger de verre', author: 'Mireille Vautrin', published: '2019-03-14', price: 18.5 },
{ id: 'b2', title: 'Sel et lanternes', author: 'Isidore Fenouil', published: '2021-11-02', price: 22 },
{ id: 'b3', title: 'Carte des rivières tranquilles', author: 'Léna Okafor', published: '2017-06-30', price: 15.9 },
{ id: 'b4', title: 'Le Jardin de l’horloger', author: 'Thomas Ruel', published: '2023-01-19', price: 24 },
{ id: 'b5', title: 'Neuf Bateaux de papier', author: 'Adèle Lindqvist', published: '2020-09-08', price: 12.75 },
{ id: 'b6', title: 'L’Hiver au quai Creux', author: 'Mireille Vautrin', published: '2024-02-27', price: 19.9 },
];
const columns: ColumnOrGroup<Book>[] = [
{ id: 'title', header: 'Titre', flex: 2, pinned: 'start' },
{ id: 'author', header: 'Auteur', flex: 1 },
{ id: 'published', header: 'Parution', type: 'day', width: 130 },
{ id: 'price', header: 'Prix', type: 'number', numberFormat: { style: 'currency', currency: 'EUR' } },
];
createGrid<Book>(document.getElementById('books')!, {
rows,
columns,
getRowId: (b) => b.id,
messages: FR,
locale: 'fr-FR',
label: 'Livres',
});

Trois réglages sont obligatoires : columns, getRowId (un identifiant stable et unique par ligne) et messages (la grille n’a pas de langue par défaut ; EN, FR et AR sont dans @dzgrid/dom/locales/*). La grille injecte son propre CSS de mise en page ; @dzgrid/theme/dzgrid.css lui donne son aspect fini (bordures, couleurs, anneau de focus). Cliquez sur un titre pour trier ; Tab entre dans la grille, les flèches vont de cellule en cellule.

Chaque fonction vient de sa propre entrée et se donne une fois dans features. Une fonction qui affiche du texte a besoin de son lot de textes fusionné dans messages ; un lot manquant lève une erreur à la création de la grille, avec la liste des clés manquantes.

import { createGrid, type GridMessages } from '@dzgrid/dom';
import { filters } from '@dzgrid/dom/filters-base';
import { pagination } from '@dzgrid/dom/pagination';
import { FR } from '@dzgrid/dom/locales/fr';
import { FR_FILTERS } from '@dzgrid/dom/locales/fr-filters';
import { FR_PAGINATION } from '@dzgrid/dom/locales/fr-pagination';
type Plant = { id: number; name: string; height: number };
const messages: GridMessages = { ...FR, text: { ...FR.text, ...FR_FILTERS.text, ...FR_PAGINATION.text } };
createGrid<Plant>(document.getElementById('plants')!, {
rows: [{ id: 1, name: 'Fougère bleue', height: 40 }],
columns: [{ id: 'name', header: 'Nom' }, { id: 'height', header: 'Hauteur (cm)', type: 'number' }],
getRowId: (p) => p.id,
messages,
pagination: { pageSize: 50 },
features: [filters(), pagination()],
});

features est lu une fois, à la création de la grille. La plupart des autres réglages sont vivants (voir plus bas).

onEvent reçoit chaque événement de la grille ; aiguillez sur type. Les problèmes (une colonne invalide, un filtre invalide, une réponse du serveur illisible) arrivent dans un événement problems : affichez-les pendant le développement.

import { createGrid } from '@dzgrid/dom';
import { FR } from '@dzgrid/dom/locales/fr';
type Tea = { id: string; name: string };
createGrid<Tea>(document.getElementById('teas')!, {
rows: [{ id: 't1', name: 'Oolong fumé' }],
columns: [{ id: 'name', header: 'Thé' }],
getRowId: (t) => t.id,
messages: FR,
selection: { mode: 'multi', checkbox: true },
onEvent: (e) => {
if (e.type === 'rowClicked' && e.row.kind === 'data') console.log('cliqué', e.row.data.name);
if (e.type === 'selectionChanged') console.log('sélectionnées', e.count);
if (e.type === 'problems') for (const p of e.problems) console.warn('dzgrid', p.code, p.path, p.detail);
},
});

Les mêmes événements s’écoutent aussi plus tard avec grid.kernel.subscribe(fn), qui rend une fonction pour arrêter l’écoute.

grid.update(patch) change des réglages. Donnez de nouveaux tableaux et objets, jamais des objets modifiés : les lignes sont reconnues par leur identifiant, si bien qu’un nouveau tableau garde le focus, la sélection et les lignes ouvertes de celles qui restent.

import { createGrid } from '@dzgrid/dom';
import { dataKey } from '@dzgrid/core';
import { FR } from '@dzgrid/dom/locales/fr';
type Kite = { id: string; name: string; span: number };
let kites: Kite[] = [{ id: 'k1', name: 'Faucon rouge', span: 120 }];
const grid = createGrid<Kite>(document.getElementById('kites')!, {
rows: kites,
columns: [{ id: 'name', header: 'Cerf-volant' }, { id: 'span', header: 'Envergure (cm)', type: 'number' }],
getRowId: (k) => k.id,
messages: FR,
});
kites = [...kites, { id: 'k2', name: 'Phalène de papier', span: 80 }];
grid.update({ rows: kites, density: 'compact' });
grid.kernel.dispatch({ type: 'sort.set', sort: [{ column: 'span', dir: 'desc' }] }, 'api');
const key = dataKey('k2');
if (key) grid.api.focusCell(key, 'name');
// Quand la page s’en va :
grid.destroy();

Les commandes (grid.kernel.dispatch) prennent une RowKey (de dataKey(id)), jamais une position : les positions changent à chaque tri et à chaque filtre.