Solution for Ext.grid.Tree to support the locked colomun (freeze column) in Sencha Extjs 7 Modern toolkit?
Nam Le
While working with Sencha Extjs, in your application, you have a component that is Ext.grid.Tree and the TreeStore, you want to make the first column/ or some columns locked (like freeze collumn) but the Ext.grid.Tree is not supported the locked colomun. You don’t want to change to another component like Ext.grid.locked.Grid or switch to the Classic toolkit because it impacted to the whole design and the functionalities.
Here is my fiddle you can give a try in this case, locked column did not work.
https://fiddle.sencha.com/#fiddle/3cmd&view/
So, the solution? I have asked here but no one has the solution excepts advice me switching to the Classic toolkit.
My solution is so simple, just create 2 grid, the first as the locked column, the second will contain all the remaining column. Implementation the scroll to make 2 grids scrolling cconsistently together. Look below:
Common.grid.GridExpander
Ext.define('Common.grid.GridExpander',{
extend: 'Ext.grid.Grid',
xtype: 'gridexpander',
plugins: {
gridcellediting: {
selectOnEdit: true,
triggerEvent: 'tap'
},
gridfilters: true
},
// ui: 'nready nready-light nready-highlight',
masked: false,
emptyText: 'No data',
defaultHeight: 79,
scrollable: false,
//minHeight: 200,
//hideHeaders: true,
variableHeights: true,
customRowHeight: 42,
striped: true,
enableAdjustSize: true,
columnMenu: {
items: {
groupByThis: null,
showInGroups: null
}
},
adjustSize: function (size) {
var grid = this;
var ch = grid.defaultHeight;
var cw = 0;
var store = grid.getStore(),
items = store && store.getData().items;
Ext.Array.each(items, function (item) {
ch += grid.customRowHeight || COMMON_CONST.GRID_ROW_HEIGHT;
});
Ext.Array.each(grid._columns, function(_c) {
cw+= _c.hidden ? 0 : (_c.width || 100);
});
if(items && items.length > 0)
grid.setHeight(ch);
if(grid._columns && grid._columns.length > 0)
grid.setWidth(cw);
},
adjustHeight: function() {
var grid = this;
var ch = grid.defaultHeight;
var store = grid.getStore(),
items = store && store.getData().items;
Ext.Array.each(items, function (item) {
ch += grid.customRowHeight || COMMON_CONST.GRID_ROW_HEIGHT;
});
if(items && items.length > 0)
grid.setHeight(ch);
},
adjustHeightViaItemStore: function() {
var grid = this;
var ch = grid.defaultHeight;
var store = grid.getStore(),
items = store && store.getData().items;
Ext.Array.each(items, function (item) {
ch += grid.customRowHeight;
});
if(items && items.length > 0)
grid.setHeight(ch);
},
adjustWidth: function() {
var grid = this;
var cw = 0;
Ext.Array.each(grid._columns, function(_c) {
cw+= _c.hidden ? 0 : (_c.width || 100);
});
if(grid._columns.length > 0)
grid.setWidth(cw);
},
listeners: {
refresh: function(sender, eOpts) {
sender.enableAdjustSize && sender.adjustSize();
}
}
});
Core.plugins.NrdRowExpander
/**
* An custom Rowexpander plugin for Ext.grid.Grid
* to support rowexpander and locked column,
* fire event onRowExpanderTap with some parameters and the grid will listen on the event for custom action
* @see [Ext.grid.Grid]{@link https://docs.sencha.com/extjs/7.0.0/modern/Ext.grid.Grid.html}
* @author Nam Le <[email protected]>
* @version 1.0.1
*/
Ext.define('Core.plugins.NrdRowExpander', {
extend: 'Ext.plugin.Abstract',
alias: ['plugin.nrdrowexpander'],
id: 'nrdrowexpander',
requires: [
'Ext.grid.cell.Expander',
// 'Ext.grid.plugin.RowExpander',
],
config: {
grid: null,
column: {
weight: -1100,
xtype: 'gridcolumn',
align: 'center',
text: '',
width: 50,
resizable: false,
hideable: false,
sortable: false,
editable: false,
ignore: true,
ignoreExport: true,
cell: {
xtype: 'expandercell',
hideMode: 'opacity',
bind: {
hidden: '{record.expandable}'
}
},
menuDisabled: true
}
},
expanderSelector: '.' + Ext.baseCSSPrefix + 'expandercell .' + Ext.baseCSSPrefix + 'icon-el',
init: function (grid) {
grid.setVariableHeights(true);
this.setGrid(grid);
},
destroy: function () {
var grid = this.getGrid(),
col = this.colInstance;
if (col && !grid.destroying) {
grid.unregisterColumn(col, true);
}
this.callParent();
},
applyColumn: function (column, oldColumn) {
return Ext.factory(Ext.apply({}, column), null, oldColumn);
},
updateGrid: function (grid) {
var me = this;
if (grid) {
grid.hasRowExpander = true;
grid.addCls(Ext.baseCSSPrefix + 'has-rowexpander');
me.colInstance = grid.registerColumn(me.getColumn());
grid.refreshScrollerSize();
grid.element.on({
tap: 'onGridTap',
delegate: me.expanderSelector,
scope: me
});
}
},
onGridTap: function (sender, element, event) {
var cell = Ext.Component.from(sender),
row = cell.row,
grid = this.getGrid();
Ext.Viewport.setMasked({
xtype: 'cmask',
message: 'Loading Tactic...'
});
// Nam: fire event rowExpanderTap with some parameters and the grid will listen on the event for custom action
grid.fireEvent('rowExpanderTap', sender, cell, row, grid, element, event);
// May have tapped on a descendant grid row. We're only interested in our own.
// if (row.getGrid() === this.getGrid()) {
// row.toggleCollapsed();
// }
},
toggleCollapsedAll: function(mode) {
var me = this,
grid = me.getCmp(),
ds = grid.getStore(),
records = ds.getRange(),
l = records.length, i,
isExpand = mode=='Expand';
Ext.Viewport.setMasked({
xtype: 'cmask',
message: (isExpand) ? 'Expanding...' : 'Collapsing...'
});
for (i = 0; i < l; i++){ //faster than store.each()
var row = grid.getViewItems()[i];
var cell =grid.getViewItems()[i].cells[0];
grid.fireEvent('toggleCollapsedAll', grid, cell, row, grid, isExpand);
}
},
});
Usage:
Ext.define('Collaborate.view.components.StatusTrackerGrid', {
extend: 'Common.grid.GridExpander',
xtype: 'statustrackerprogramgrid',
requires: [
'Core.overrides.grid.Row',
],
selectable:{
mode: 'SINGLE'
},
});
Create two component that the first is Freeze and the Second is free.
{
xtype: 'hlayout',
layout: {
pack: 'start'
},
height: '2', // <= Trick
items: [
{
xtype: 'statustrackerprogramgrid',
reference: 'programlockedgridRef0',
publishes: 'selections',
cls: 'status-tracker-grid',
enableAdjustSize: false,
store:[],
scrollable: true,
plugins: {
gridcellediting: true,
nrdrowexpander: true, // <= Use custom plugin
},
columns: preDefinedColumn,
itemConfig: {
viewModel: true,
body: {
xtype: 'container',
reference: 'nameRowItemcf',
}
},
listeners: {
scroll: 'onGridScroll', // <= sync scrolling between two grid
rowExpanderTap: 'onRowExpanderTap',
toggleCollapsedAll: 'onToggleCollapsedAll',
select: 'onRowSelected',
edit: 'onUpdateProgramByModel',
}
},
{
xtype: 'statustrackerprogramgrid',
reference: 'programlockedgridRef1',
publishes: 'selections',
cls: 'status-tracker-grid gridRef1',
// userCls: 'program',
flex: 1,
enableAdjustSize: false,
store:[],
scrollable: true,
plugins: {
gridcellediting: true,
nrdrowexpander: true, // <= Use custom plugin
perfectscroll: true
},
columns: preDefinedColumnGrid1,
itemConfig: {
viewModel: true,
body: {
xtype: 'popuptacticdialog',
cls: 'status-tracker-grid-tactic-container content-item shadow',
//programId: record.getId(),
}
},
listeners: {
scroll: 'onGridScroll', // <= sync scrolling between two grid
rowExpanderTap: 'onRowExpanderTap',
select: 'onRowSelected'
// edit: 'onUpdateProgramByModel',
}
},
]
}
Result:

I will update the fiddle later.
- Extjs 7.0.0 Modern toolkit
-Nam Le, nready.net