In the Bryntum nested grid, I need to understand how we can detect whether the store changes contain modified records or newly added records.
For example, when we edit a record in the nested grid and then check the store, it correctly contains the modified record:
When we edit a record in the nested grid and then click Save, the store correctly contains the changes, and modified.count returns the number of modified records.
import shared from '../_shared/shared.module.js?491841';
import { DataGenerator, RandomGenerator, DateHelper, Store, StringHelper, GridRowModel, Grid } from '../../build/grid.module.js?491841';
//region "lib/data.js"
const randomGenerator = new RandomGenerator();
const getEmployees = () => {
const data = DataGenerator.generateData(3);
for (const row of data) {
DateHelper.add(row.start, row.id * 2, 'month', false);
row.email = `${row.name.toLowerCase().replaceAll(' ', '.')}@example.com`;
}
return data;
};
const getTimeRows = (employees) => {
const
tasks = DataGenerator.generateEvents({ viewStartDate : new Date(), viewEndDate : new Date(), nbrResources : 1, nbrEvents : 35 }).events.map(e => e.name),
rows = [];
let id = 0;
for (const employee of employees) {
for (let i = 0; i < Math.ceil(Math.random() * 10); i++) {
id += 1;
rows.push({
id,
employeeId : employee.id,
name : randomGenerator.fromArray(tasks),
hours : Math.ceil(Math.random() * 100),
attested : Math.random() > 0.5
});
}
}
return rows;
};
//endregion
// These two model classes and two stores use the built-in data-relations feature to connect related records to each other.
class Employee extends GridRowModel {
static fields = [
'id',
'firstName',
'name',
{ name : 'start', type : 'date' },
'email'
];
// Example how to set up a "calculated" field
get unattested() {
return this.timeRows?.reduce((acc, r) => acc + (r.attested ? 0 : 1), 0);
}
// Example how to set up a "calculated" field
get totalTime() {
return this.timeRows?.reduce((acc, r) => acc + r.hours, 0);
}
}
class TimeRow extends GridRowModel {
static fields = ['id', 'employeeId', 'project', 'hours', 'attested'];
// The relations config, will set up the relationship between the two stores and model classes
static relations = {
employee : {
foreignKey : 'employeeId', // The id of the "other" record
foreignStore : 'employeeStore', // Must be set on the record's store
relatedCollectionName : 'timeRows', // The field in which these records will be accessible from the "other" record
propagateRecordChanges : true // This makes the outer Grid react to the expanded Grid(s) changes
}
};
}
const employeeStore = new Store({
modelClass : Employee,
data : getEmployees()
});
const timeRowStore = new Store({
modelClass : TimeRow,
employeeStore, // Must be set, see relations config above
data : getTimeRows(employeeStore.records)
});
const grid = new Grid({
appendTo : 'container',
features : {
rowExpander : {
// The widget config declares what type of Widget will be created on each expand
widget : {
cls : 'timerow-grid', // CSS class added to the outer element
type : 'grid',
autoHeight : true, // Grid resizes to fit all rows
columns : [
{ text : 'Project', field : 'name', flex : 1 },
{ text : 'Hours spent', field : 'hours', width : 135, type : 'number', align : 'end' },
{ text : 'Attested', field : 'attested', width : 110, type : 'check' }
],
// Bottom toolbar
tbar : [
'->',
// Add button, which adds a row to the expanded grid and starts editing it
{
text : 'Add',
icon : 'b-icon-add',
rendition : 'text',
onClick : ({ source }) => {
const
grid = source.up('grid'),
expandedRecord = grid.owner.features.rowExpander.getExpandedRecord(grid),
[newRecord] = grid.store.add({ name : null, hours : 0, employeeId : expandedRecord.id });
debugger;
// store.changes.added.count
}
},
{
// Button that sets all rows as "attested"
text : 'Save button',
icon : 'fa fa-save',
rendition : 'text',
onClick : async({ source }) => {
const { store } = source.up('grid');
debugger;
var storeChanges = await store.changes,
modifiedRows = storeChanges.modified,
addedRows = storeChanges.added;
}
}
]
},
dataField : 'timeRows' // Tells rowExpander widget to populate it's store from this field
}
},
columns : [
{ text : 'Employee#', field : 'id', width : 130, align : 'center' },
{ text : 'Name', field : 'name', flex : 1 },
{ text : 'Start date', field : 'start', flex : 1, type : 'date' },
{
text : 'Email',
field : 'email',
flex : 1,
htmlEncode : false, // To be able to use HTML in the renderer
renderer : ({ value }) => StringHelper.xss`<i class="fa fa-envelope"></i><a href="mailto:${value}">${value}</a>`
}, {
text : 'Attested',
field : 'unattested',
width : 110,
editor : false,
renderer({ value, cellElement }) {
cellElement.style.color = value ? '#e53f2c' : '#4caf50';
return value ? value + ' left' : 'All done';
}
},
{ text : 'Total time', field : 'totalTime', width : 120, align : 'center', editor : false }
],
store : employeeStore,
listeners : {
renderRows : ({ source }) => {
// This will expand third row at a state where the theme has loaded
const rowExpander = source.features.rowExpander;
source.store.forEach(record => {
rowExpander.expand(record);
});
},
once : true
}
});
Forum post
In the Bryntum nested grid, I need to understand how we can detect whether the store changes contain modified records or newly added records.
For example, when we edit a record in the nested grid and then check the store, it correctly contains the modified record:
const { store } = source.up('grid');
const storeChanges = await store.changes,
modifiedRows = storeChanges.modified;
However, in the case of newly added records, when we check store.changes, it returns null. As a result, we cannot retrieve the added records:
addedRows = storeChanges.added;
https://bryntum.com/products/grid/examples/nested-grid/
When we edit a record in the nested grid and then click Save, the store correctly contains the changes, and modified.count returns the number of modified records.