@browser.style/data-grid
Version:
Dynamic data grid component with sorting, filtering, and pagination support
132 lines (118 loc) • 3.72 kB
JavaScript
import PrintPreview from '../../print-preview/index.js';
import { applySorting, filterData } from './render.table.js';
export function setupPrint(context) {
try {
let printPreview = document.querySelector('print-preview');
if (!printPreview) {
printPreview = document.createElement('print-preview');
if (!(printPreview instanceof HTMLElement)) {
throw new Error('PrintPreview component failed to initialize');
}
document.body.appendChild(printPreview);
}
context.printPreview = printPreview;
// Generate unique template name for this grid instance
if (!context.templateId) {
context.templateId = `data-grid-${crypto.randomUUID()}`;
}
const template = (data) => {
// Validate input data
if (!Array.isArray(data)) {
throw new Error('Print data must be an array');
}
if (!context.state?.thead) {
throw new Error('Table headers not initialized');
}
const visibleColumns = context.state.thead.filter(col => !col.hidden);
return `
<style>
table { width: 100%; border-collapse: separate; border-spacing: 2ch 0; }
th { text-align: start; }
</style>
<paper-sheet>
<table part="table">
<thead>
<tr>${visibleColumns.map(col => `<th>${col.label}</th>`).join('')}</tr>
</thead>
<tbody part="tbody">
${data.map(row => `
<tr>
${visibleColumns.map(col => {
return `<td>${row[col.field] || ''}</td>`;
}).join('')}
</tr>
`).join('')}
</tbody>
</table>
</paper-sheet>
`;
};
printPreview.addTemplate(context.templateId, template, {
'font-family': 'ff-system',
'font-size': 'small',
'margin-top': '15mm',
'margin-right': '10mm',
'margin-bottom': '15mm',
'margin-left': '10mm',
'orientation': 'portrait',
'paper-size': 'A4'
});
} catch (error) {
context.log(`Error setting up print: ${error}`, '#F00');
throw error;
}
}
export function printTable(context, directPrint = false) {
try {
if (!context.state?.tbody?.length) {
context.log('No data to print', '#F00');
return;
}
if (!context.printPreview) {
setupPrint(context);
}
// First, create a sorted copy of the full dataset if sorting is active
let sortedData = [...context.state.tbody];
sortedData = context.state.sortIndex > -1 ? applySorting(context, sortedData) : sortedData;
let dataToPrint = [];
const { printOptions, page, itemsPerPage, selected } = context.state;
switch (printOptions) {
case 'search':
dataToPrint = filterData(context, sortedData);
break;
case 'page':
const startIndex = page * itemsPerPage;
dataToPrint = sortedData.slice(startIndex, startIndex + itemsPerPage);
break;
case 'selected':
if (!selected?.size) {
throw new Error('No rows selected');
}
const keyFields = context.state.thead.filter(col => col.key).map(col => col.field);
dataToPrint = sortedData.filter(row => {
const compositeKey = keyFields.map(field => row[field]).join(',');
return selected.has(compositeKey);
});
break;
case 'all':
default:
dataToPrint = sortedData;
}
if (!dataToPrint.length) {
throw new Error('No data to print');
}
context.printPreview.setAttribute('template', context.templateId);
context.printPreview.setAttribute('use-template', '');
context.printPreview.data = dataToPrint;
if (directPrint) {
context.printPreview.print();
} else {
context.printPreview.preview();
}
} catch (error) {
context.log(`Print error: ${error.message}`, '#F00');
context.dispatchEvent(new CustomEvent('dg:printerror', {
detail: { error: error.message, printOptions: context.state.printOptions }
}));
}
}