As many of you I was wandering why Sencha didn't include the possibility to set a column width to a specified 25% of the screen. So here is a how to enable this feature by yourself.
DEMO:
https://dl.dropboxusercontent.com/u/2056172/KeepAlive/GridPrecentageWidth/ExampleProject/index.html
Full Project: https://dl.dropboxusercontent.com/u/2056172/KeepAlive/GridPrecentageWidth/GridColumnPercentage.zip
Full Tutorial:
First we need a sample grid and set the width of the columns to a percentage value, for example '25%'
Ext.define('ExampleProject.view.SampleGrid', {
extend: 'Ext.grid.Grid',
alias: 'widget.samplegrid',
requires: [
'Ext.grid.column.Column'
],
config: {
height: '100%',
id: 'samplegrid',
store: 'MyStore',
title: 'MyGrid',
columns: [
{
xtype: 'column',
itemId: 'column1',
width: '40%',
dataIndex: 'data1',
text: 'Column1'
},
{
xtype: 'column',
itemId: 'column2',
width: '25%',
dataIndex: 'data2',
text: 'Column2'
},
{
xtype: 'column',
itemId: 'column3',
width: '25%',
dataIndex: 'data3',
text: 'Column3'
}
],
listeners: [
{
fn: 'onGridPainted',
event: 'painted'
},
{
fn: 'onGridWidthChange',
event: 'widthchange'
}
]
}
)};
All we need to to now is to call a function on the painted event which will let us render the percentage value to a pixel value and overwrite the width on the column.
So add a painted listener because we need to set the new size when the grid is painted:
onGridPainted: function(element, eOpts) {
this.renderColumnPercentage(element);
},
And now calculate the pixels from the percentage value:
var grid = this,
columnArr = grid.getColumns(),
numberOfCols = columnArr.length,
clientWidth = element.getAttribute('clientWidth');
columnArr.forEach(
function(column, index, array) {
var perWidth = column.getWidth(); // Percentage or Pixel width --> '25%' || '123'
if (!Ext.isNumeric(perWidth) && perWidth) { // Checking for a percentage value
perWidthNum = perWidth.substr(0,perWidth.length-1) / 100; // Numeric Width --> 0.25
pxWidth = clientWidth * perWidthNum; // Width in Pixel --> 123
}
// Header width
column.bodyElement.setWidth(pxWidth);
column.refreshSizeState();
// Each column has its own class
if (! column.getCellCls()) {
column.setCellCls(createCellCssClass(pxWidth));
} else {
// Query doms for a class --> 1 Class = 1 Column
var elements = Ext.query('.' + column.getCellCls()),
newClass = createCellCssClass(pxWidth),
oldClass = column.getCellCls();
// Loop doms and replace old class with new one
Ext.Array.each(elements, function(ele, index, elementsItSelf) {
ele.classList.remove(column.getCellCls());
ele.classList.add(newClass);
});
column.setCellCls(newClass);
}
}
);
function createCellCssClass(pxWidth) {
var className = 'cell-' + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
var css = document.createElement('style');
css.type = 'text/css';
var styles = '.' + className + ' { width: ' + pxWidth + 'px !important; }';
if (css.styleSheet)
css.styleSheet.cssText = styles;
else
css.appendChild(document.createTextNode(styles));
document.getElementsByTagName("head")[0].appendChild(css);
return className;
}
The width is set on the elements level to prevent loosing the percentage value on the column level.
Last we need to call the same function when
widthchanged is fired on the grid itself because this will need resizing for all columns.
Just add a listener to perform the resizing again:
onGridWidthChange: function(component, value, oldValue, eOpts) {
this.renderColumnPercentage(component.bodyElement);
},
Read more ...