PDA

View Full Version : auto resize columns in ext 4.0.0



sraghura201
16 Aug 2011, 12:08 PM
I have a column that uses a custom image renderer. I need the column to expand to fit the size of the image. Since
meta.style="width:auto !important;" and using a tdCls which specifies width:auto don't work, I need to resize them manually.


I went by the discussion in this thread and used the code posted by animal
http://www.sencha.com/forum/showthread.php?20536-What-happened-to-Ext.grid.Grid.autoSizeColumns


Ext.override(Ext.CompositeElement, {
getTextWidth: function() {
var i, e, els = this.elements, result = 0;
for(i = 0; e = Ext.get(els[i]); i++) {
result = Math.max(result, e.getTextWidth.apply(e, arguments));
}
return result;
}
});

Ext.override(Ext.grid.GridPanel, {
autoSizeColumns: function() {
this.colModel.suspendEvents();
for (var i = 0; i < this.colModel.getColumnCount(); i++) {
this.autoSizeColumn(i);
}
this.colModel.resumeEvents();
this.view.refresh(true);
},

autoSizeColumn: function(c) {
var col = this.view.el.select("td.x-grid3-td-" + this.colModel.getColumnId(c) + " div:first-child");
if (col) {
var w = col.getTextWidth() + Ext.get(col.elements[0]).getFrameWidth('lr') + 2;
this.colModel.setColumnWidth(c, w);
return w;
}
}
})


The catch is that Ext.CompositeElementLite is not overrideable and overriding Ext.ComponentElement gets the same "col.getTextWidth is not a function" error mentioned in that thread. So does anybody have a pointer about what exactly should be overridden to contain getTextWidth()?

sraghura201
22 Aug 2011, 6:49 AM
I think this should be a simple case of overriding some other class. Any help appreciated.

Alternatively is there some other renderer - related way to autosize the width of a column

janwijffels
22 Aug 2011, 7:34 AM
Hi,

I'm having the same problem when setting up ext.grid.panel.
Have you already encountered a solution?

newbie.scott
30 Aug 2011, 7:32 AM
Any solution to this problem please? I am struck as well..

Cheers
N
ewbieScott

sraghura201
30 Aug 2011, 9:06 AM
I switched to using extjs-3.2 where the code works

skirtle
31 Aug 2011, 6:37 PM
I've had a go at writing a plugin to solve this in ExtJS 4. Example usage:


Ext.create('Ext.grid.Panel', {
height: 300,
plugins: Ext.create('Ext.ux.grid.AutoWidthColumnsPlugin'),
renderTo: Ext.getBody(),
store: store,
width: 300,
columns: [
{dataIndex: 'name', header: 'Name', autoWidth: true},
{dataIndex: 'type', header: 'Type', autoWidth: 'single'},
{dataIndex: 'age', header: 'Age', flex: 1}
]
});

I wrote it for 4.0.6. Testing against 4.0.2 and 4.0.5 gave slightly different behaviour in that it couldn't shrink a column below its initial width. To get behaviour comparable to 4.0.6 just set the initial column width to something small.

In a vanilla grid it works fine but if you're using other plugins or features it may not work. However, I've tried to make it easy to extend and with any luck you'd just need to tweak the CSS selector.

Other than the standard plugin methods there are 2 methods you might want to call manually: refresh() and autoWidthColumn(column). Under normal circumstances this won't be necessary as they are called automatically but you can get finer-grained control over when resizing occurs by calling them yourself.


Ext.define('Ext.ux.grid.AutoWidthColumnsPlugin', {
extend: 'Ext.AbstractPlugin',

init: function(grid) {
this.bindGrid(grid);
},

bindGrid: function(grid) {
this.disable();
this.grid = grid;
this.enable();
},

refresh: function() {
var columns = this.grid.columns,
index = 0,
len = columns.length;

for ( ; index < len ; ++index) {
var column = columns[index];

if (column.autoWidth) {
if (this.autoWidthColumn(column) && column.autoWidth === 'single') {
column.autoWidth = false;
}
}
}
},

autoWidthColumn: function(column) {
var me = this,
grid = me.grid,
selector = me.columnCellsSelector(Ext.isNumber(column) ? grid.columns[column] : column),
el = grid.getEl(),
cells = el ? el.query(selector) : [],
index = 0,
len = cells.length,
newWidth = 1;

if (!len) {
return false;
}

for ( ; index < len ; ++index) {
newWidth = Math.max(newWidth, me.calculateWidth(cells[index]));
}

column.setWidth(newWidth);

return newWidth;
},

columnCellsSelector: function(column) {
return '.x-grid-cell-' + column.id + ' .x-grid-cell-inner';
},

calculateWidth: function(cell) {
var el = Ext.fly(cell);

return el.getTextWidth() + el.getFrameWidth('lr');
},

destroy: function() {
this.bindGrid(null);
},

enable: function() {
var me = this;

if (me.disabled && me.grid) {
me.grid.getView().on('refresh', me.refresh, me);
}

me.callParent();
},

disable: function() {
var me = this;

if (me.grid) {
me.grid.getView().un('refresh', me.refresh, me);
}

me.callParent();
}
});

perl.dev
22 Feb 2012, 2:37 PM
Hello. I was curious to know if anyone has had success with this plugin? It looks promising.

Also, does anyone know if Sencha plans to add an 'autoWidth' property in the future?

Thanks,

Scott

skirtle
22 Feb 2012, 4:19 PM
I've got a much improved version of that plugin now. I'll send you a copy over PM. Once 4.1 goes GA I'll publish it properly.

perl.dev
23 Feb 2012, 6:55 AM
I got it. We will implement and I'll give some feedback. Thanks again!

eeshuz
23 Feb 2012, 8:04 PM
Great implementation, thank you. However, I don't think it accommodates for when the length of the header is more than the length of the longest value of the column, thus the header is hidden in this scenario. Maybe it should check to see if the longest value is less than the header, and if so, make the width the header (plus however many pixels it is for the menu drop-down arrow). I would do this but I am so clueless about ExtJS and javascript it's not even funny - just following tutorials and reading to make things work. Thanks again.

skirtle
23 Feb 2012, 8:07 PM
I'll send you a copy of what I sent to perl.dev. It does take the header width into consideration.

dnorman
11 Mar 2012, 5:25 PM
Can you post the most recent version of this?

skirtle
12 Mar 2012, 1:26 AM
I've sent you the latest copy over PM.

As I mentioned earlier, I'll release it properly in the UX forum once 4.1 goes GA.

flamant
29 Mar 2012, 6:15 AM
Hi skirtle,

I tried your plugin and in my case I get the following error



config is undefined
if (!config.cmp && Ext.global.console) { ->classes.js (line 6220)


I added the following code in a "includes" file



Ext.define('Ext.ux.grid.AutoWidthColumnsPlugin', {
extend: 'Ext.AbstractPlugin',

init: function(grid) {
this.bindGrid(grid);
},

bindGrid: function(grid) {
this.disable();
this.grid = grid;
this.enable();
},

refresh: function() {
var columns = this.grid.columns,
index = 0,
len = columns.length;

for ( ; index < len ; ++index) {
var column = columns[index];

if (column.autoWidth) {
if (this.autoWidthColumn(column) && column.autoWidth === 'single') {
column.autoWidth = false;
}
}
}
},

autoWidthColumn: function(column) {
var me = this,
grid = me.grid,
selector = me.columnCellsSelector(Ext.isNumber(column) ? grid.columns[column] : column),
el = grid.getEl(),
cells = el ? el.query(selector) : [],
index = 0,
len = cells.length,
newWidth = 1;

if (!len) {
return false;
}

for ( ; index < len ; ++index) {
newWidth = Math.max(newWidth, me.calculateWidth(cells[index]));
}

column.setWidth(newWidth);

return newWidth;
},

columnCellsSelector: function(column) {
return '.x-grid-cell-' + column.id + ' .x-grid-cell-inner';
},

calculateWidth: function(cell) {
var el = Ext.fly(cell);

return el.getTextWidth() + el.getFrameWidth('lr');
},

destroy: function() {
this.bindGrid(null);
},

enable: function() {
var me = this;

if (me.disabled && me.grid) {
me.grid.getView().on('refresh', me.refresh, me);
}

me.callParent();
},

disable: function() {
var me = this;

if (me.grid) {
me.grid.getView().un('refresh', me.refresh, me);
}

me.callParent();
}
});


I added


plugins: Ext.create('Ext.ux.grid.AutoWidthColumnsPlugin')



in my grid as a property

and I added



autoWidth: true


for one column

May be there is a new release of that plugin ?

skirtle
29 Mar 2012, 8:26 AM
4.1 has not yet been released. As I have said previously, I will publish a proper release of the latest plugin once 4.1 is released.

The error you are hitting is caused by debug code in AbstractPlugin. Pass in an empty config to Ext.create and it'll work fine.

I'll send you the latest code via PM.

rg-flow
25 Apr 2012, 5:41 AM
Hi,

Ext 4.1 is finally out - could you please share the code with us.

Regards
Roger

skirtle
25 Apr 2012, 5:51 AM
I'll try to release it in the next few days. The version I had working against the early 4.1 betas doesn't quite work against 4.1 GA. I'll update this thread when I've got it working.

alexmipego
23 May 2012, 5:28 AM
Hi, I was wondering if you had the time to fix the code for the 4.1 release and if you are ready to share the code? I checked your site but still nothing :(

If you could share it now we all would appreciate it, or if you aren't done just yet, could you PM it to me? It could be a real life saver!

Thanks!

dnorman
23 May 2012, 9:42 AM
Try my version. It's a work in progress, and may have bugs, but seems to work well enough for me.
I spent a lot of time making it fast.
In my tests, it's substantially faster than skirtle's version B)

( Tested against 4.1.0 )



Ext.define('Ext.ux.ColumnAutoWidthPlugin', {
extend: 'Ext.AbstractPlugin',
autoUpdate: true,
constructor: function(config) {
var me = this;
Ext.apply(me, config);
},
init: function(grid) {
var me = this;


me.disable();
me.grid = grid;
grid.columnAutoWidthPlugin = me;
me.enable();
},
destroy: function() {
this.clearListeners();
},
enable: function() {
var me = this, grid = me.grid;

if (me.autoUpdate && me.disabled && grid){
var view = grid.getView();

var viewChangeDT = new Ext4.util.DelayedTask(function(){
me.onViewChange();
});
var viewChange = function(){ viewChangeDT.delay(100) };


me.mon(view, 'refresh', viewChange );
me.mon(view, 'itemadd', viewChange );
me.mon(view, 'itemremove', viewChange );
me.mon(view, 'itemupdate', viewChange );
me.mon(view, 'afteritemexpand', viewChange );

me.mon(grid, 'columnshow', me.onColumnChange, me, { buffer: 100 });
}

me.callParent();
},
disable: function() {
this.clearManagedListeners();
this.callParent();
},
onColumnChange: function(ct, column) {
if( this.suspendAutoSize ) return;
if ( column.autoWidth ) this.doAutoSize([column]);
},
onViewChange: function() { this.refresh() },
refresh: function() {
var me = this, grid = me.grid;
if ( me.suspendAutoSize || !grid.rendered || !grid.getView().rendered ) return;

var cols = me.getAutoCols();
if ( cols.length ) me.doAutoSize( cols );
},
getAutoCols: function(){
var me = this, cols = me.grid.columns, out = [], i = cols.length, col;

while(i--){
col = cols[i];
if ( col.autoWidth ) out.push(col);
}

return out;
},
getTableResizers: function() {
var els = this.grid.getView().getEl().query( '.' + Ext.baseCSSPrefix + 'grid-table-resizer');

// Grouping feature - first table wraps everything and can be ignored
if (els.length > 1 && Ext.fly(els[0]).contains(els[1])) {
els.shift();
}

return els;
},
getColumnResizers: function(column, config) {
// Grab the <th> rows (one per table) that are used to size the columns
var els = this.grid.getEl().query( '.' + Ext.baseCSSPrefix + 'grid-col-resizer-' + column.id);

// Grouping feature - first table wraps everything and needs to be ignored
if (els.length > 1 && Ext.fly(els[0]).parent('table').contains(els[1])) {
els.shift();
}

return els;
},
doAutoSize: function( resizeCols ){
var me = this,
view = me.grid.getView();

if( me.suspendAutoSize ) return;

var start = new Date().getTime();

Ext.batchLayouts(function(){

var viewDisplayMode = view.el.getStyle('display');

var tableWidths = {};

// set the table resizers to auto
Ext.each( me.getTableResizers(), function(el) {
el = Ext.fly(el);
tableWidths[ Ext.id(el) ] = el.getWidth();
el.setStyle({ 'table-layout': 'auto', width: 'auto' });
});
//console.log('ColumnAutoWidthPlugin','autofy table resizers took', 0-start + (start = new Date().getTime()), 'ms');

// auto-ify the each of the cell resizers.
Ext.each(resizeCols, function(col){
if( col.el ){
col.el.setStyle('width', 'auto');
}
Ext.each( me.getColumnResizers(col) , function(el) {
el.style.width = 'auto';
//Ext.fly(el).setStyle('width', '1px');
});
});

// no further dom changes beyond this point - to avoid reflows

//console.log('ColumnAutoWidthPlugin','autofy column resizers took', 0-start + (start = new Date().getTime()), 'ms');

Ext.each(resizeCols, function(col){
var els = me.getColumnResizers(col), newWidth = 0;

if( col.el ) newWidth = Ext.num(col.el.dom.scrollWidth,0);

Ext.each(els, function(el) {
newWidth = Math.max(el.scrollWidth, newWidth); // scrollwidth should be cheaper
});

newWidth = Math.max( newWidth + 2, col.minAutoWidth || 0 );

if( newWidth == col.width ){
var widthStr = String(col.width) + 'px';
Ext.each( me.getColumnResizers(col) , function(el) {
el.style.width = widthStr;
});
col.el.setStyle('width', widthStr);
} else if( col.el ){
col.setWidth( newWidth );
} else {
col.width = newWidth;
}
});

//console.log('ColumnAutoWidthPlugin','measure and set took', 0-start + (start = new Date().getTime()), 'ms');

// put the table resizers back how you found them
Ext.iterate(tableWidths, function(id, width) {
Ext.fly(id).setStyle('table-layout', '').setWidth(width);
});

//console.log('ColumnAutoWidthPlugin','restore table layout took', 0-start + (start = new Date().getTime()), 'ms');
});

console.log('ColumnAutoWidthPlugin','doAutoSize took', 0-start + (start = new Date().getTime()), 'ms');

}

});

webfriend13
14 Jun 2012, 12:48 AM
Hey Skirtle,

Any plans to release the plugin now ?

youngcm2
19 Jul 2012, 9:44 AM
Did you publish the plugin?

skirtle
19 Jul 2012, 6:19 PM
No. Haven't even come close to having time to work on it. If I do I'll update this thread.

At this point I'd advise trying to adjust the plugin dnorman posted to meet your needs. I've not really dug in to see what he's doing but by the looks of it he's using a roughly similar approach and getting better performance from much less code.

jonasby
3 Sep 2012, 4:56 AM
dnorman, I tried using your code with Ext 4.1.1, but the resize is not affecting the data rows, only the column headers. (I also removed the '4' from 'Ext4.' and included the Observable mixin...)

have you made any updates?

dnorman
4 Sep 2012, 5:15 PM
Hey jonasby

yes there is a newer version.
See example here:

http://dnorman.github.com/ExtJS-Patches/example/ColumnAutoWidthPlugin.html (http://dnorman.github.com/ExtJS-Patches/example/ColumnAutoWidthPlugin.html)

I hope this works for you. let me know if you find any bugs :D


dnorman, I tried using your code with Ext 4.1.1, but the resize is not affecting the data rows, only the column headers. (I also removed the '4' from 'Ext4.' and included the Observable mixin...)

have you made any updates?

paragdreams
30 Oct 2012, 4:06 AM
I've got a much improved version of that plugin now. I'll send you a copy over PM. Once 4.1 goes GA I'll publish it properly.

Hi Skirtle,

I used plugin you posted in this thread and it works almost fine for me. As you mentioned that you have improved version of this plugin, can you please send it to me to try out?
Thanking you in advance.

-Parag

paragdreams
30 Oct 2012, 6:21 AM
Hey jonasby

yes there is a newer version.
See example here:

http://dnorman.github.com/ExtJS-Patches/example/ColumnAutoWidthPlugin.html (http://dnorman.github.com/ExtJS-Patches/example/ColumnAutoWidthPlugin.html)

I hope this works for you. let me know if you find any bugs :D

Hi dnorman,

I tried your plugin latest version to set auto column width. It works faster and as expected on all browsers except IE8 in my case. Do you have any idea of what changes I need to do to make it work similar to other browsers? In IE it shows column width so large and my horizontal scroll bar needs to keep pressed to move to see next column.
Thanking you in advance for your help.

-Parag

milas
13 Dec 2012, 4:27 AM
Hi.
Great implementation.
but, did it work with locking grid?

dnorman
15 Dec 2012, 9:00 PM
Hi.
Great implementation.
but, did it work with locking grid?

Hey milas... A locking grid is actually two different grids. I believe that if you specify the plugin as config (not an object), it should work properly.

milas
16 Dec 2012, 2:04 AM
Hey milas... A locking grid is actually two different grids. I believe that if you specify the plugin as config (not an object), it should work properly.
Thank you very much!

panbayi
26 Sep 2013, 7:11 AM
@dnorman
Hi,dnorman,thanks for you brilliant work.But it seems that it dosn't work well with ExtJS 4.2.It tried it ,but it can only autosize according to the length of the header text,but not to the length of content in the cell.
Looking forward to the solution with ExtJS 4.2.

Hey jonasby

yes there is a newer version.
See example here:

http://dnorman.github.com/ExtJS-Patches/example/ColumnAutoWidthPlugin.html (http://dnorman.github.com/ExtJS-Patches/example/ColumnAutoWidthPlugin.html)

I hope this works for you. let me know if you find any bugs :D