An issues-only repository for the Bryntum project management component suite which includes powerful Grid, Scheduler, Calendar, Kanban Task Board and Gantt chart components all built in pure JS / CSS / TypeScript
/* globals bryntum : true */
import { LightningElement } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import GRID from '@salesforce/resourceUrl/bryntum_grid';
import { columns, data } from './data';
export default class Grid_component extends LightningElement {
renderedCallback() {
if (this.bryntumInitialized) {
return;
}
this.bryntumInitialized = true;
Promise.all([
loadScript(this, GRID + '/grid.lwc.module.js'),
loadStyle(this, GRID + '/grid.stockholm.css'),
])
.then(() => {
this.createGrid();
});
}
createGrid() {
window.grid = new bryntum.grid.Grid({
features : {
regionResize : true,
group : {
field : 'skills.skill'
},
rowExpander : {
// When configuring different Widgets for different Grid regions, the different widget configuration objects
// needs to be wrapped in an object with the region names as properties
widget : {
// This is the widget configuration for the left region
locked : {
type : 'container',
cls : 'action-panel',
items : [
{
type : 'button',
text : 'Add skill',
width : '100%',
onClick : ({ source }) => {
const
{ rowExpander } = source.up('grid').features,
// With the 'getExpandedRecord' function you can get the expanded record that the
// current widget belongs to
record = rowExpander.getExpandedRecord(source.owner),
{ skills } = record,
id = skills.last?.id || 0;
skills.add({
id : id + 1,
skill : 'New skill',
level : 1,
active : true,
verified : false
});
}
},
{
type : 'button',
text : 'Clear skills',
width : '100%',
onClick : ({ source }) => {
const record = source.up('grid').features.rowExpander.getExpandedRecord(source.owner);
record.skills.removeAll();
}
},
{
type : 'button',
text : 'Deactivate',
width : '100%',
onClick : ({ source }) => {
// This button toggles the "Active" value of the expanded record
const record = source.up('grid').features.rowExpander.getExpandedRecord(source.owner);
record.active = !record.active;
},
listeners : {
paint({ source }) {
// Set the Activate/Deactivate button's text upon expanding the row
const
button = this,
grid = source.up('grid'),
expandedRecord = grid.features.rowExpander.getExpandedRecord(source.owner);
if (!expandedRecord.active) {
button.text = 'Activate';
}
// When record changes (either from clicking the button, or editing the outer grid)
// Update the Activate/Deactivate button's text
grid.store.on({
update({ record }) {
if (expandedRecord === record) {
button.text = record.active ? 'Deactivate' : 'Activate';
}
},
// To remove this listener when the row collapses
thisObj : button
});
}
}
}
]
},
// This is the widget configuration for the right region
normal : {
type : 'grid',
cls : 'skills-grid',
// The dataField config needs to be placed inside the widget config object when there is multiple
// regions and widgets
dataField : 'skills',
autoHeight : true,
minHeight : null,
emptyText : 'No skills assigned',
fillLastColumn : false,
columns : [
{ field : 'id', text : 'No.', type : 'number', width : 100, align : 'center' },
{ field : 'skill', text : 'Skill', flex : 1, maxWidth : 400 },
{ field : 'level', text : 'Level', type : 'number', width : 100, align : 'center' },
{ field : 'verified', text : 'Verified', type : 'check', width : 100 }
]
}
}
}
},
columns : [
{ field : 'employeeId', text : 'Employee no.', type : 'number', width : 110, region : 'locked', align : 'center', renderer : ({ value, record }) => record.isPhantom ? '' : value },
{ field : 'name', text : 'Name', width : 150, region : 'locked' },
{ field : 'city', text : 'City', width : 170, region : 'normal' },
{ field : 'age', text : 'Age', type : 'number', width : 120, region : 'normal', align : 'center' },
{ field : 'start', text : 'Start', type : 'date', width : 180, region : 'normal' },
{
field : 'email',
text : 'Email',
width : 270,
region : 'normal',
htmlEncode : false,
renderer : ({ value }) => {
return bryntum.grid.StringHelper.xss`<i class="b-fa b-fa-envelope"></i><a href="mailto:${value}">${value}</a>`;
}
},
{ field : 'active', text : 'Active', type : 'check', width : 120, region : 'normal' },
{ field : 'notes', text : 'Notes', width : 1000, region : 'normal' }
],
appendTo: this.template.querySelector('.container'),
store : {
fields : [
{ name : 'skills', type : 'store', storeClass : window.bryntum.grid.Store, modelClass : window.bryntum.grid.GridRowModel }, 'active', 'notes'
]
}
});
const data = window.bryntum.grid.StringHelper.safeJsonParse('[{"skills":[],"_groupValue":"Angular","skill":"Angular"},{"id":1,"skills":[{"id":1,"skill":"Angular","level":3,"verified":true},{"id":2,"skill":"BASIC","level":3,"verified":false},{"id":3,"skill":"Vue","level":1,"verified":true},{"id":4,"skill":"JavaScript","level":1,"verified":true}],"title":"Row 0","name":"Don A Taylor","firstName":"Don","surName":"Taylor","city":"Montreal","team":"Paris Tigers","age":30,"food":"Salad","color":"Black","score":880,"rank":99,"start":"2019-02-06T00:00:00+03:00","finish":"2019-02-21T00:00:00+03:00","time":"2020-01-01T02:10:00+03:00","percent":13,"done":false,"rating":2,"active":true,"relatedTo":2,"notes":"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.","employeeId":1,"email":"don.a.taylor@example.com"},{"id":"2_link_819172dd-4ed0-4e9b-89ed-65533c10e71b","skills":[{"id":1,"skill":"PASCAL","level":2,"verified":true},{"id":2,"skill":"Java","level":3,"verified":true},{"id":3,"skill":"Angular","level":2,"verified":true},{"id":4,"skill":"PHP","level":2,"verified":true}],"title":"Row 1","name":"Jane B Scott","firstName":"Jane","surName":"Scott","city":"Stockholm","team":"Barcelona Ducks","age":32,"food":"Burger","color":"Orange","score":640,"rank":23,"start":"2019-01-23T00:00:00+03:00","finish":"2019-01-30T00:00:00+03:00","time":"2020-01-01T20:00:00+03:00","percent":81,"done":false,"rating":2,"active":false,"relatedTo":2,"notes":"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.","employeeId":2,"email":"jane.b.scott@example.com"},{"skills":[],"_groupValue":"BASIC","skill":"BASIC"},{"id":"1_link_8369bf4b-3d53-4d87-953c-436ca12c4f03","skills":[{"id":1,"skill":"Angular","level":3,"verified":true},{"id":2,"skill":"BASIC","level":3,"verified":false},{"id":3,"skill":"Vue","level":1,"verified":true},{"id":4,"skill":"JavaScript","level":1,"verified":true}],"title":"Row 0","name":"Don A Taylor","firstName":"Don","surName":"Taylor","city":"Montreal","team":"Paris Tigers","age":30,"food":"Salad","color":"Black","score":880,"rank":99,"start":"2019-02-06T00:00:00+03:00","finish":"2019-02-21T00:00:00+03:00","time":"2020-01-01T02:10:00+03:00","percent":13,"done":false,"rating":2,"active":true,"relatedTo":2,"notes":"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.","employeeId":1,"email":"don.a.taylor@example.com"},{"id":"3_link_2162cfdf-e110-4798-8c6b-87fa46e53916","skills":[{"id":1,"skill":"JavaScript","level":3,"verified":true},{"id":2,"skill":"Vue","level":2,"verified":false},{"id":3,"skill":"BASIC","level":2,"verified":false}],"title":"Row 2","name":"Mike C Ewans","firstName":"Mike","surName":"Ewans","city":"Montreal","team":"Washington Dogs","age":15,"food":"Carbonara","color":"Teal","score":260,"rank":14,"start":"2019-02-07T00:00:00+03:00","finish":"2019-02-10T00:00:00+03:00","time":"2020-01-01T02:55:00+03:00","percent":11,"done":false,"rating":3,"active":true,"relatedTo":2,"notes":"Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?","employeeId":3,"email":"mike.c.ewans@example.com"},{"skills":[],"_groupValue":"Java","skill":"Java"},{"id":"2_link_07c629f5-bd70-4bea-af84-53fd4fa3a743","skills":[{"id":1,"skill":"PASCAL","level":2,"verified":true},{"id":2,"skill":"Java","level":3,"verified":true},{"id":3,"skill":"Angular","level":2,"verified":true},{"id":4,"skill":"PHP","level":2,"verified":true}],"title":"Row 1","name":"Jane B Scott","firstName":"Jane","surName":"Scott","city":"Stockholm","team":"Barcelona Ducks","age":32,"food":"Burger","color":"Orange","score":640,"rank":23,"start":"2019-01-23T00:00:00+03:00","finish":"2019-01-30T00:00:00+03:00","time":"2020-01-01T20:00:00+03:00","percent":81,"done":false,"rating":2,"active":false,"relatedTo":2,"notes":"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.","employeeId":2,"email":"jane.b.scott@example.com"},{"skills":[],"_groupValue":"JavaScript","skill":"JavaScript"},{"id":"1_link_f752fd2c-756b-44e9-a1dc-d9c9a6ce91b7","skills":[{"id":1,"skill":"Angular","level":3,"verified":true},{"id":2,"skill":"BASIC","level":3,"verified":false},{"id":3,"skill":"Vue","level":1,"verified":true},{"id":4,"skill":"JavaScript","level":1,"verified":true}],"title":"Row 0","name":"Don A Taylor","firstName":"Don","surName":"Taylor","city":"Montreal","team":"Paris Tigers","age":30,"food":"Salad","color":"Black","score":880,"rank":99,"start":"2019-02-06T00:00:00+03:00","finish":"2019-02-21T00:00:00+03:00","time":"2020-01-01T02:10:00+03:00","percent":13,"done":false,"rating":2,"active":true,"relatedTo":2,"notes":"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.","employeeId":1,"email":"don.a.taylor@example.com"},{"id":3,"skills":[{"id":1,"skill":"JavaScript","level":3,"verified":true},{"id":2,"skill":"Vue","level":2,"verified":false},{"id":3,"skill":"BASIC","level":2,"verified":false}],"title":"Row 2","name":"Mike C Ewans","firstName":"Mike","surName":"Ewans","city":"Montreal","team":"Washington Dogs","age":15,"food":"Carbonara","color":"Teal","score":260,"rank":14,"start":"2019-02-07T00:00:00+03:00","finish":"2019-02-10T00:00:00+03:00","time":"2020-01-01T02:55:00+03:00","percent":11,"done":false,"rating":3,"active":true,"relatedTo":2,"notes":"Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?","employeeId":3,"email":"mike.c.ewans@example.com"},{"skills":[],"_groupValue":"PASCAL","skill":"PASCAL"},{"id":2,"skills":[{"id":1,"skill":"PASCAL","level":2,"verified":true},{"id":2,"skill":"Java","level":3,"verified":true},{"id":3,"skill":"Angular","level":2,"verified":true},{"id":4,"skill":"PHP","level":2,"verified":true}],"title":"Row 1","name":"Jane B Scott","firstName":"Jane","surName":"Scott","city":"Stockholm","team":"Barcelona Ducks","age":32,"food":"Burger","color":"Orange","score":640,"rank":23,"start":"2019-01-23T00:00:00+03:00","finish":"2019-01-30T00:00:00+03:00","time":"2020-01-01T20:00:00+03:00","percent":81,"done":false,"rating":2,"active":false,"relatedTo":2,"notes":"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.","employeeId":2,"email":"jane.b.scott@example.com"},{"skills":[],"_groupValue":"PHP","skill":"PHP"},{"id":"2_link_7b635a7c-b7fb-4983-8887-4f0529a4777f","skills":[{"id":1,"skill":"PASCAL","level":2,"verified":true},{"id":2,"skill":"Java","level":3,"verified":true},{"id":3,"skill":"Angular","level":2,"verified":true},{"id":4,"skill":"PHP","level":2,"verified":true}],"title":"Row 1","name":"Jane B Scott","firstName":"Jane","surName":"Scott","city":"Stockholm","team":"Barcelona Ducks","age":32,"food":"Burger","color":"Orange","score":640,"rank":23,"start":"2019-01-23T00:00:00+03:00","finish":"2019-01-30T00:00:00+03:00","time":"2020-01-01T20:00:00+03:00","percent":81,"done":false,"rating":2,"active":false,"relatedTo":2,"notes":"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.","employeeId":2,"email":"jane.b.scott@example.com"},{"skills":[],"_groupValue":"Vue","skill":"Vue"},{"id":"1_link_bef7c540-c8aa-4258-8bf8-44b8ca5f7cc5","skills":[{"id":1,"skill":"Angular","level":3,"verified":true},{"id":2,"skill":"BASIC","level":3,"verified":false},{"id":3,"skill":"Vue","level":1,"verified":true},{"id":4,"skill":"JavaScript","level":1,"verified":true}],"title":"Row 0","name":"Don A Taylor","firstName":"Don","surName":"Taylor","city":"Montreal","team":"Paris Tigers","age":30,"food":"Salad","color":"Black","score":880,"rank":99,"start":"2019-02-06T00:00:00+03:00","finish":"2019-02-21T00:00:00+03:00","time":"2020-01-01T02:10:00+03:00","percent":13,"done":false,"rating":2,"active":true,"relatedTo":2,"notes":"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.","employeeId":1,"email":"don.a.taylor@example.com"},{"id":"3_link_ff35202f-8556-4898-9416-977de6fca0d7","skills":[{"id":1,"skill":"JavaScript","level":3,"verified":true},{"id":2,"skill":"Vue","level":2,"verified":false},{"id":3,"skill":"BASIC","level":2,"verified":false}],"title":"Row 2","name":"Mike C Ewans","firstName":"Mike","surName":"Ewans","city":"Montreal","team":"Washington Dogs","age":15,"food":"Carbonara","color":"Teal","score":260,"rank":14,"start":"2019-02-07T00:00:00+03:00","finish":"2019-02-10T00:00:00+03:00","time":"2020-01-01T02:55:00+03:00","percent":11,"done":false,"rating":3,"active":true,"relatedTo":2,"notes":"Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?","employeeId":3,"email":"mike.c.ewans@example.com"}]');
window.grid.store.data = data;
window.grid.features.rowExpander.expand(grid.store.getAt(7));
}
RowExpander doesn't work in Salesforce because of security restrictions
Forum post
Hi,