joakim.l wrote: ↑Tue Feb 13, 2024 11:08 amHi,
As long as you use the same version on all Bryntum packages in your package.json it should be fine.
On your old branch, you can use 5.4.0 on all packages. In your new branch, you can use 5.6.6 on all packages.
You will most likely have to run
npm install
after switching branches to have the correct packages installed.
Hi Joakim,
We tried the example you gave and it worked for us. The issue we are facing is described below.
We have added the listener to the row expander and did the hide/show of the grids/container based on the button clicks. We need to have the row expander event triggered on each button click but it does so for only one (currently it works for the button that is clicked first). You can refer to the code snippet provided below.
import { DataGenerator, RandomGenerator, DateHelper, Grid, GridRowModel, Store, StringHelper } from '../../build/grid.module.js?474079';
import shared from '../_shared/shared.module.js?474079';
const randomGenerator = new RandomGenerator();
export const getEmployees = () => {
const data = DataGenerator.generateData(25);
for (const row of data) {
DateHelper.add(row.start, row.id * 2, 'month', false);
row.email = `${row.name.toLowerCase().replaceAll(' ', '.')}@example.com`;
}
return data;
};
export 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;
};
// These two model classes and two stores uses the built-in data-relations feature to connect related records to each other.
class Employee extends GridRowModel {
static fields = ['id', 'firstName', 'name', 'start', '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
}
};
}
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 toggleRow = ({ source }) => {
const
{ record } = source.cellInfo,
{ rowExpander } = source.closest('grid').features,
{ name } = source,
expandedWidgets = rowExpander.getExpandedWidgets(record);
if (expandedWidgets) {
const
{ timeGrid, notesGrid } = expandedWidgets.normal.widgetMap,
targetGrid = name === 'time' ? timeGrid : notesGrid,
otherGrid = name === 'time' ? notesGrid : timeGrid;
if (targetGrid.hidden) {
targetGrid.hidden = false;
}
else if (otherGrid.hidden) {
rowExpander.collapse(record);
}
else {
targetGrid.hidden = true;
}
}
else {
record._showInitially = name;
rowExpander.expand(record);
}
};
const grid = new Grid({
appendTo : 'container',
features : {
rowExpander: {
column: { hidden: true },
enableAnimations: true,
// The widget config declares what type of Widget will be created on each expand
renderer({ record }) {
let currentRecord = record;
const { _showInitially } = record;
record._showInitially = null;
return {
dataset: { id: record.id },
type: "container",
layout: "vbox",
items: {
timeGrid: {
hidden: _showInitially !== "time",
cls: "timerow-grid", // CSS class added to the outer element
type: "grid",
autoHeight: true, // Grid resizes to fit all rows
features: {
headerMenu: false,
cellEdit: false,
cellMenu: false,
},
columns: [
{
field: "branch",
text: "branch",
editor: false,
autoWidth: true,
},
{
field: "Ctrl",
text: "Ctrl",
editor: false,
autoWidth: true,
},
],
tbar: [
{
cls: "btn btn-outline-primary btn-sm",
type: "button",
text: "Show More",
onClick: () => {
vm.toggleDetailsMore(currentRecord, "", "2");
},
},
{
cls: "btn btn-outline-primary btn-sm",
type: "button",
text: "Show All",
onClick: () => {
vm.toggleDetailsAll(currentRecord, "", "3");
},
},
"",
],
store: {
data: [],
},
},
notesGrid: {
hidden: _showInitially !== "notes",
cls: "timerow-grid", // CSS class added to the outer element
type: "container",
autoHeight: true,
items: [
{
type: "textfield",
ref: "txtnotes",
cls: "col-md-3",
placeholder: "Notes",
value: "",
},
{
type: "combo",
cls: "col-md-2",
ref: "cmbgroup",
displayField: "label",
items: [],
placeholder: "Notes Group",
},
{
type: "combo",
ref: "cmbuser",
cls: "col-md-3",
valueField: "label",
items: [],
placeholder: "Assigned To",
},
{
type: "button",
text: "Submit",
ref: "btn1",
cls: "b-raised b-blue",
onClick: function ({ source }) {
vm.onNoteSubmit(
currentRecord,
currentRecord.parentIndex,
0,
source.closest("container").values,
source.closest("container").items[5].store
);
},
},
{
type: "button",
ref: "btn2",
text: "Submit & Notify",
cls: "b-raised b-green",
onClick: ({ source }) => {
vm.onNoteSubmit(
currentRecord,
currentRecord.parentIndex,
1,
source.closest("container").values,
source.closest("container").items[5].store
);
},
},
{
type: "grid",
ref: "notes_grid",
cls: "col-md-12",
autoHeight: true,
features: {
headerMenu: false,
cellEdit: false,
cellMenu: false,
},
columns: [
{
text: "Assigned To",
field: "NameAssign",
autoWidth: true,
},
{
text: "Note",
field: "Des",
autoWidth: true,
},
{ text: "Added By", field: "Name", autoWidth: true },
],
store: {
data: [],
},
},
],
},
},
};
},
listeners: {
expand: async (source) => {
try {
const { record } = source;
console.log(
"recordaaaa",
record,
record._showInitially,
record.data._showInitially
);
if (record.data._showInitially == "notes") {
console.log("here we do the api call and bind the data in grid.");
console.log("Notes Row expanded successfully.");
} else {
console.log("here we do the api call and bind the data in combos and grid.");
console.log("Details Row expanded successfully.");
}
} catch (error) {
console.error("Error expanding row:", error);
}
},
},
},
},
columns : [
{ text : 'Employee no.', field : 'id', width : 100, align : 'center' },
{ text : 'Name', field : 'name', flex : 1 },
{ text : 'Total time', field : 'totalTime', width : 100, align : 'center', editor : false },
{
field : 'show_details',
text : '',
width : 200,
default : true,
action : true,
editor : false,
type : 'widget',
align : 'center',
widgets : [
{
type : 'button',
name : 'time',
cls : 'b-raised',
color : 'b-green',
text : '',
onClick : toggleRow
}
],
renderer : ({ record, widgets, grid }) => {
const expanded = grid.features.rowExpander.getExpandedWidgets(record)?.normal.widgetMap.timeGrid;
widgets[0].text = expanded && !expanded.hidden ? 'Hide Details' : 'Show Details';
if (
parseInt(record.Matched) === 3 ||
parseInt(record.Posted) === 1
) {
widgets[0].disabled = true;
}
else {
widgets[0].disabled = false;
}
}
},
{
field : 'show_detailsnote',
text : '',
width : 200,
default : true,
action : true,
editor : false,
type : 'widget',
align : 'center',
widgets : [
{
type : 'button',
cls : 'b-raised',
color : 'b-green',
name : 'notes',
text : '',
onClick : toggleRow
}
],
renderer : ({ record, widgets, grid }) => {
const expanded = grid.features.rowExpander.getExpandedWidgets(record)?.normal.widgetMap.notesGrid;
widgets[0].text = expanded && !expanded.hidden ? 'Hide Note' : 'Show Note';
}
}
],
store : employeeStore
});
You can put the same code in the example https://bryntum.com/products/grid/examples/nested-grid/ and see that it will only do a console log for the button clicked first, which means the expander calls only once on the button click. If the Details button is clicked first then it will log a message for that else it will log for the notes grid.
I hope the problem statement is clear and we're able to explain it well.
Many thanks for the support provided so far.