Working with Data
PGrid keeps your data in a DataTable that you reach via grid.data. It supports two input formats and exposes a small CRUD + search API.
Data formats
The dataModel config tells PGrid how to interpret your data.
Object rows (default)
dataModel: {
format: 'rows',
fields: ['name', 'email', 'role'],
data: [
{ name: 'Ada', email: 'ada@example.com', role: 'Engineer' },
{ name: 'Linus', email: 'linus@example.com', role: 'Manager' }
]
}
Tuple arrays
Useful when your data comes from CSV or a database driver that returns rows as arrays.
dataModel: {
format: 'array',
fields: ['name', 'email', 'role'],
data: [
['Ada', 'ada@example.com', 'Engineer'],
['Linus', 'linus@example.com', 'Manager']
]
}
fields tells PGrid the column order so it can normalize each tuple into an object internally.
Reading values
PGrid distinguishes between row id (stable, assigned at insert) and row index (position in the currently visible projection — affected by sort/filter/search).
// By visible row index
const value = grid.data.getDataAt(rowIndex, 'email');
// By stable row id
const rowId = grid.data.getRowId(rowIndex);
const value = grid.data.getData(rowId, 'email');
// Whole row
const row = grid.data.getRowDataAt(rowIndex); // by index
const row = grid.data.getRowData(rowId); // by id
Writing values
Use the model when you have visible coordinates; use the data table when you have a row id.
// By coordinates (visible)
grid.model.setDataAt(rowIndex, colIndex, newValue);
// By row id + field
grid.data.setData(rowId, 'salary', 80000);
If autoUpdate: true is set, the affected cell re-renders automatically.
Add, insert, remove
grid.data.addRow({ name: 'Grace', email: 'grace@example.com', role: 'Engineer' });
grid.data.insertRow(0, newRow); // at the top
grid.data.removeRow(rowId);
grid.data.removeRowAt(rowIndex);
grid.data.removeAllRows();
grid.view.reRender();
Live demo: Dynamic data.
Search & filter
The DataTable maintains a separate visible projection that you can filter without losing the original data.
// Single regex pattern, all fields (case-insensitive)
grid.data.search('ada');
// Restrict to specific fields
grid.data.search('engineer', ['role', 'department']);
// Multiple patterns OR-match
grid.data.search(['^ada', '^linus']);
// Reset
grid.data.clearSearch();
After mutating the projection, call grid.view.reRender(). Live demo: Search & filter.
Listening for changes
The data table emits dataChanged with a list of updates.
grid.data.listen('dataChanged', (e) => {
e.updates.forEach(u => {
// u.changeType: 'fieldChange' | 'rowAdded' | 'rowRemoved' | 'global'
// u.rowId, u.field, u.prevData, u.data
console.log(u);
});
});
You can also intercept and cancel writes by registering an extension:
const validateNumeric = {
dataBeforeUpdate(e) {
if (e.field === 'salary' && isNaN(parseFloat(e.data))) {
e.cancel = true;
} else if (e.field === 'salary') {
e.data = parseFloat(e.data);
}
}
};
new PGrid({ /* … */ extensions: [validateNumeric] });
See Extensions for the full list of hooks.
Bulk updates
For batched mutations, use freeze / unfreeze to suppress per-write events.
grid.data.freeze();
for (const row of bigImport) grid.data.addRow(row);
grid.data.unfreeze();
grid.view.reRender();