Export and print
The grid writes what it shows to a file — CSV, Excel or JSON — and prints it as a real table. The demo has the three files and the print above it, and the same in its right-click menu: sort or filter first, the file follows.
CSV and Excel
Section titled “CSV and Excel”csvExport({ canExport }) from @dzgrid/dom/export writes the grid’s rows to a CSV file, and to an Excel file
(.xlsx) with xlsx: true (texts -export). The file holds the visible columns in their order, the sort and the
filters; values are written as values (ISO days, instants in the grid’s zone, numbers a spreadsheet can add up), or as
the cells show them with text: 'display'.
import { createGrid, type GridMessages } from '@dzgrid/dom';import { csvExport } from '@dzgrid/dom/export';import { EN } from '@dzgrid/dom/locales/en';import { EN_EXPORT } from '@dzgrid/dom/locales/en-export';
type Kettle = { id: string; model: string; litres: number; boughtOn: string };
const exporter = csvExport({ canExport: true, xlsx: true, separator: ';', fileName: ({ scope }) => `kettles-${scope}`,});const messages: GridMessages = { ...EN, text: { ...EN.text, ...EN_EXPORT.text } };
createGrid<Kettle>(document.getElementById('kettles')!, { rows: [{ id: 'k1', model: 'Whistling Wren', litres: 1.7, boughtOn: '2024-12-01' }], columns: [ { id: 'model', header: 'Model' }, { id: 'litres', header: 'Litres', type: 'number' }, { id: 'boughtOn', header: 'Bought on', type: 'day' }, ], getRowId: (k) => k.id, messages, selection: { mode: 'multi' }, features: [exporter],});
exporter.bind(document.getElementById('csv')!, { scope: 'displayed' });exporter.bind(document.getElementById('xlsx')!, { scope: 'displayed', format: 'xlsx' });document.getElementById('selected')!.addEventListener('click', async () => { const outcome = await exporter.run('selected'); // 'done' | 'refused' | 'failed' | 'cancelled' | 'busy' console.log(outcome);});import { Component } from '@angular/core';import { DzGrid, DzgExport, type DzgColumnOrGroup } from '@dzgrid/angular';import { csvExport } from '@dzgrid/dom/export';import { EN } from '@dzgrid/dom/locales/en';import { EN_EXPORT } from '@dzgrid/dom/locales/en-export';
type Kettle = { id: string; model: string; litres: number; boughtOn: string };
const exporter = csvExport({ canExport: true, xlsx: true, separator: ';', fileName: ({ scope }) => `kettles-${scope}` });
@Component({ selector: 'app-kettles', imports: [DzGrid, DzgExport], template: ` <button type="button" [dzgExport]="exporter" dzgExportScope="displayed">CSV file</button> <button type="button" [dzgExport]="exporter" dzgExportScope="selected">The selected rows</button> <dz-grid [rows]="rows" [columns]="columns" [getRowId]="rowId" [messages]="messages" [selection]="{ mode: 'multi' }" [features]="features" />`,})export class Kettles { readonly rows: Kettle[] = [{ id: 'k1', model: 'Whistling Wren', litres: 1.7, boughtOn: '2024-12-01' }]; readonly columns: DzgColumnOrGroup<Kettle>[] = [ { id: 'model', header: 'Model' }, { id: 'litres', header: 'Litres', type: 'number' }, { id: 'boughtOn', header: 'Bought on', type: 'day' }, ]; readonly rowId = (k: Kettle) => k.id; readonly messages = { ...EN, text: { ...EN.text, ...EN_EXPORT.text } }; readonly exporter = exporter; readonly features = [exporter];}import '@dzgrid/element/define';import type { DzGridElement } from '@dzgrid/element';import { csvExport } from '@dzgrid/dom/export';import { EN } from '@dzgrid/dom/locales/en';import { EN_EXPORT } from '@dzgrid/dom/locales/en-export';
type Kettle = { id: string; model: string; litres: number; boughtOn: string };
const exporter = csvExport({ canExport: true, xlsx: true, separator: ';', fileName: ({ scope }) => `kettles-${scope}` });const grid = document.querySelector<DzGridElement<Kettle>>('dz-grid')!;grid.columns = [ { id: 'model', header: 'Model' }, { id: 'litres', header: 'Litres', type: 'number' }, { id: 'boughtOn', header: 'Bought on', type: 'day' },];grid.getRowId = (k) => k.id;grid.messages = { ...EN, text: { ...EN.text, ...EN_EXPORT.text } };grid.features = [exporter];grid.settings = { selection: { mode: 'multi' } };grid.rows = [{ id: 'k1', model: 'Whistling Wren', litres: 1.7, boughtOn: '2024-12-01' }];
exporter.bind(document.getElementById('csv')!, { scope: 'displayed' });exporter.bind(document.getElementById('xlsx')!, { scope: 'displayed', format: 'xlsx' });- Scopes:
'displayed'(the rows shown now: the current page when paged),'selected','all'(every row the query matches, on every page; the filters still apply). canExport: true, or a function that may refuse ({ ok: false, reason }) — a place for your own permission rule.- A text starting like a formula (
=,+,-,@) gets a leading'so a spreadsheet does not run it; a number such as-5never does.numbers: 'excel'(the default) writes the locale’s decimal mark when the separator is;,numbers: 'raw'the machine form.csv: 'text'on a column keeps identifiers such as0123as text. - The file is built in chunks so the page never freezes;
exporter.cancel()stops it,onProgressfollows it. - With server data, the grid holds only some rows: give
exportAll(request, { signal, progress }), which asks your server for the file (the request carries the query in wire form) and returns{ url }or{ blob }. - The right-click menu offers the same:
contextMenu({ use: { csv: exporter, xlsx: exporter.xlsx } }). - In Angular:
<button [dzgExport]="exporter" dzgExportScope="displayed">(directiveDzgExport).
Every option of csvExport() is on its page.
The same feature writes a JSON file: run(scope, { format: 'json' }) or bind(button, { format: 'json' }) — no
option to switch it on, its code is fetched at the first JSON export. The file is one array of objects keyed by the
column ids, in screen order, with raw values: numbers, true / false, days 'YYYY-MM-DD', instants as ISO UTC text
with Z, enum codes, null for an empty cell (text: 'display' writes what the cells show). Group and totals rows
are not written; canExport and exportAll see request.format === 'json'.
import type { CsvExport } from '@dzgrid/dom/export';
declare const exporter: CsvExport;exporter.bind(document.getElementById('json')!, { scope: 'all', format: 'json' });Import a file
Section titled “Import a file”fileImport({ onRows }) from @dzgrid/dom/import reads a CSV or Excel (.xlsx) file dropped on the grid, or picked
with your own button (api(grid).bind(button), the keyboard path), in the browser. The first non-empty line is the
header, matched to your columns by title or id (case and accents aside); each cell goes through its column’s type as
if typed in the grid’s language. The grid never changes its rows: onRows(rows, problems, file) gets one object
per line, at each column’s field (or id), and you decide — add them, replace, or show a preview. A refused cell is
left out and told as a problem (import-cell, path rows[3].qty, its code), never with its value. Excel files are
inflated by the browser’s DecompressionStream; the reading code is fetched at the first file. Texts -import.
import { createGrid, type GridMessages } from '@dzgrid/dom';import { fileImport } from '@dzgrid/dom/import';import { EN } from '@dzgrid/dom/locales/en';import { EN_IMPORT } from '@dzgrid/dom/locales/en-import';
type Jar = { id: string; flavour: string; grams: number };let jars: Jar[] = [{ id: 'j1', flavour: 'Fig', grams: 250 }];const messages: GridMessages = { ...EN, text: { ...EN.text, ...EN_IMPORT.text } };const importer = fileImport({ accept: ['csv', 'xlsx'], onRows: (rows, problems) => { if (problems.length) console.warn(problems); jars = [...jars, ...rows.map((r, i) => ({ ...(r as Omit<Jar, 'id'>), id: `new-${Date.now()}-${i}` }))]; grid.update({ rows: jars }); },});const grid = createGrid<Jar>(document.getElementById('jars')!, { rows: jars, columns: [{ id: 'flavour', header: 'Flavour' }, { id: 'grams', header: 'Grams', type: 'number' }], getRowId: (j) => j.id, messages, features: [importer],});importer.api(grid)!.bind(document.getElementById('import-button')!);print(grid, { title }) from @dzgrid/dom/print prints the rows as they are on screen — same columns, order, sort and
filters, not only the rows scrolled into view — as a real table: headers repeated on each page, no row cut in two,
right to left in Arabic, a dark theme printed light (texts -print, CSS print.css). At most 5 000 rows
(maxRows); beyond, a line says how many were printed. A grid with server pages prints the page shown.
import { createGrid, type GridMessages } from '@dzgrid/dom';import { print } from '@dzgrid/dom/print';import { printOnMenu } from '@dzgrid/dom/print-menu';import { EN } from '@dzgrid/dom/locales/en';import { EN_PRINT } from '@dzgrid/dom/locales/en-print';import '@dzgrid/theme/dzgrid.css';import '@dzgrid/theme/print.css';
type Bell = { id: string; tower: string; note: string };
const messages: GridMessages = { ...EN, text: { ...EN.text, ...EN_PRINT.text } };const grid = createGrid<Bell>(document.getElementById('bells')!, { rows: [{ id: 'b1', tower: 'Saltmarsh', note: 'F sharp' }], columns: [{ id: 'tower', header: 'Tower' }, { id: 'note', header: 'Note' }], getRowId: (b) => b.id, messages,});
document.getElementById('print')!.addEventListener('click', () => void print(grid, { title: 'Bells of the coast' }));printOnMenu(grid, { title: 'Bells of the coast' }); // the browser's own Ctrl+P prints the whole grid tooprint(grid, { header: false }) leaves the header rows out (they are printed by default, even on a grid with
headers: 'hidden'). print is a function, not a feature: nothing is loaded until it is called. printOnMenu(grid)
makes the browser’s own print command (Ctrl+P, the File menu) print the whole grid as well; without it, that command
prints only what the page shows. In Angular, pass ctrl.grid() to both.