PDA

View Full Version : TableGridView - 25-50% faster GridView implementation



Condor
24 Aug 2010, 5:37 AM
I created a TableGridView extension for Ext 3.2 that uses a <table> to render all rows. In contrast to Animal's TableGridView (http://www.sencha.com/forum/showthread.php?77908-TableGridView-lightweight-GridView-based-upon-a-lt-table-gt), this GridView extension does support column widths and column resizing.

Advantages:
- Reducing the number of DOM elements increases rendering speed (Firefox by about 50%, IE by about 30%, WebKit by about 25%).
- The column width only needs to be specified once for all cells in a column, so changing the column width is very fast (up to 99% depending on the grid size).

Disadvantages:
- TableGridView does not support enableRowBody (so no RowExpander either).
- Some GridPanel plugins will need to be modified to work with this view.
- Some column renderers might need some changes to display correctly.

Note: I haven't tested this very thoroughly, so please post any problems you find.

wki01
9 Sep 2010, 4:48 AM
Does not work, you can provide a small test case?
Thanks

Condor
9 Sep 2010, 5:09 AM
What doesn't work?

Here is an example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ext="http://www.extjs.com" xml:lang="en" lang="en">
<head>
<title>Test</title>
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
<link rel="stylesheet" type="text/css" href="TableGridView.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base-min.js"></script>
<script type="text/javascript" src="../../ext-all-min.js"></script>
<script type="text/javascript" src="TableGridView.js"></script>
<script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';
Ext.onReady(function () {
var data = [], columns = [], i, j, r;
for (i = 0; i < 200; i++) {
r = [];
for (j = 0; j < 50; j++) {
r[j] = i * j;
}
data[i] = r;
}
for (j = 0; j < 50; j++) {
columns[j] = {
header: 'Field ' + (j + 1),
dataIndex: 'field' + (j + 1)
};
}
new Ext.Viewport({
layout: 'fit',
items: [{
xtype: 'grid',
store: data,
columns: columns,
view: new Ext.ux.grid.TableGridView()
}]
});
});
</script>
</head>
<body>
</body>
</html>

wki01
9 Sep 2010, 5:47 AM
With the latest beta of 3.3 and does not work.
I tried now with the 3.1 and it works.

Please consider the operation even in this situation:
http://www.sencha.com/forum/showthread.php?76406-jsonStore-gt-panel.items&p=371353%20#post371353

Version of the animal does not work in this situation.

thanks

Condor
9 Sep 2010, 7:39 AM
GridView changed in Ext 3.3. You will need an updated version of every grid extension out there!

stevenwilford
10 Sep 2010, 12:00 AM
TableGridView does not support enableRowBody (so no RowExpander either).

Could you not leverage <td colspan="n"></td> to assist in row expander support?

Condor
10 Sep 2010, 12:20 AM
Yes, I could support row bodies with additional rows, but that would make TableGridView slower. Maybe in a separate class.

I'm also thinking about creating a TableGroupingView that uses a <tbody> for every group.

dan_b
10 Sep 2010, 5:26 AM
GridView changed in Ext 3.3. You will need an updated version of every grid extension out there!

Condor, is there any info on what's changed that will break all grid extensions in 3.3?

Condor
10 Sep 2010, 5:39 AM
The main difference is that renderUI is split into two methods:
1. renderUI does not actually render the UI, but only returns the HTML content to render the grid.
2. afterRenderUI contains all old renderUI code that executed after the grid was rendered.

wki01
25 Oct 2010, 1:20 AM
Hello condor.
You can post the version of this extension for Ext 3.3?
thanks

Condor
25 Oct 2010, 1:30 AM
I'll work on it, but I'm rather busy now, so it could take some time.

tobiu
26 Oct 2010, 2:54 PM
hi condor and community,

i hope it is ok if i port this one over to ext 3.3.0.
as condor mentioned, it is now afterRenderUI, so we had to change 6 letters inside the code (line 170).


kind regards
tobiu

wki01
26 Oct 2010, 11:22 PM
Yes, now it works.
The version of Animal has a very nice thing for me.
The columns are automatically sized.
It is also possible to implement here?
Thanks

Condor
27 Oct 2010, 1:26 AM
Yes, the DOM structure would allow for width:auto, but the GridView implementation would have to be adapted to get the width of the auto width columns after they have rendered.

Steffen Hiller
7 Nov 2010, 7:55 AM
My Ext.ux.PrinterFriendly plugin works pretty much the same way. Allows printing + has better performance for displaying/printing large datasets. But any additional UI features that you don't need for printing are disabled/removed.

Thanks tobiu for the afterRenderUI thing, that was the only thing that broke my plugin in 3.3.0 as well.

techakone
21 Feb 2011, 4:58 PM
Hi Condor,
I am working with 3.2.1 and after fixing a couple of things in your extension i was able to use it in my grid as is. I have to make the grids we are using 508 compliants and one of the violations with the current implementation of the GridPanel is that
1) Rows must be associated with the proper header
2)Rows and headers must belong to the same table.

With your component i was able to achieve 1) partly as now all rows belong to the same table. I tried building on your component to have the Grid header and the grid body all be part of the same table. I have been at it all day now and I am stuck so i kindly request your and the community's help. Basically I get the grid to render with the following problems:


The width on the table row elements is not properly calculated. The headers are rendered fine but the row elements themselves are out of wack.

Here is what it look like:

24782

Here are the changes i made to your code, as well as the overrides i brought in from GridView.js:


initTemplates: function () {
var ts = this.templates || {};
if(!ts.master){
ts.master = new Ext.Template(
'<div class="x-grid3" hidefocus="true">',
'<div class="x-grid3-viewport">',
'<table class="x-grid3-row-table ux-table-grid " border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
'<colgroup>{cols}</colgroup>',
'<thead style="{ostyle}" class="x-grid3-header x-grid3-header-inner x-grid3-header-offset"><tr class="x-grid3-hd-row">{headers}</tr></thead>',
'<tbody class="x-grid3-scroller x-grid3-body" style="{bstyle}">{body}</tbody>',
'</table>',
'</div>',
'<div class="x-grid3-resize-marker">&#160;</div>',
'<div class="x-grid3-resize-proxy">&#160;</div>',
'</div>'
);
}

if(!ts.header){
ts.header = new Ext.Template('{headers}');
}


if(!ts.hcell){
ts.hcell = new Ext.Template(
'<td class="x-grid3-hd x-grid3-cell x-grid3-td-{id} {css}" style="{style}"><div {tooltip} {attr} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">', this.grid.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
'{value}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
'</div></td>'
);
}
if (!ts.body) {
ts.body = new Ext.Template(

'{rows}'

);
}
if (!ts.col) {
ts.col = new Ext.Template(
'<col style="{style}" />'
);
}
if (!ts.row) {
ts.row = new Ext.Template(
'<tr class="x-grid3-row {alt}" style="{tstyle}">{cells}</tr>'
);
}
if (!ts.cell) {
ts.cell = new Ext.Template('<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css} x-grid3-cell-inner x-grid3-col-{id}" style="{style}" tabIndex="0" {cellAttr} unselectable="on" {attr}>',
'{value}',
'</td>'
);
}
this.templates = ts;
Ext.ux.grid.TableGridView.superclass.initTemplates.call(this);
},
getRows: function () {
return this.hasRows() ? this.mainHd.dom.tBodies[0].rows: [];
},
getCols: function() {
return this.hasRows() ? this.mainHd.childNodes : [];
},


I have also updated renderUI to render everything but the table rows:


renderUI: function () {
var templates = this.templates,
cols = [],
col = this.templates.col,
i, len = this.cm.getColumnCount(),
header = this.renderHeaders(),
body = '&#160;';
for(i = 0; i < len; i++) {
cols.push(col.apply({
style: this.getColStyle(i)
}));
}
var html = templates.master.apply({
body: body,
cols:cols.join(''),
headers: header,
ostyle: 'width:' + this.getOffsetWidth() + ';',
bstyle: 'width:' + this.getTotalWidth() + ';'
});
var g = this.grid;
g.getGridEl().dom.innerHTML = html;
this.initElements();
Ext.fly(this.innerHd).on('click', this.handleHdDown, this);
this.mainHd.on({
scope: this,
mouseover: this.handleHdOver,
mouseout: this.handleHdOut,
mousemove: this.handleHdMove
});
this.scroller.on('scroll', this.syncScroll, this);
if (g.enableColumnResize !== false) {
this.splitZone = new Ext.grid.GridView.SplitDragZone(g, this.mainHd.dom);
}
if (g.enableColumnMove) {
this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g, this.innerHd);
this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom);
}
if (g.enableHdMenu !== false) {
this.hmenu = new Ext.menu.Menu({
id: g.id + '-hctx'
});
this.hmenu.add({
itemId: 'asc',
text: this.sortAscText,
cls: 'xg-hmenu-sort-asc'
}, {
itemId: 'desc',
text: this.sortDescText,
cls: 'xg-hmenu-sort-desc'
});
if (g.enableColumnHide !== false) {
this.colMenu = new Ext.menu.Menu({
id: g.id + '-hcols-menu'
});
this.colMenu.on({
scope: this,
beforeshow: this.beforeColMenuShow,
itemclick: this.handleHdMenuClick
});
this.hmenu.add('-', {
itemId: 'columns',
hideOnClick: false,
text: this.columnsText,
menu: this.colMenu,
iconCls: 'x-cols-icon'
});
}
this.hmenu.on('itemclick', this.handleHdMenuClick, this);
}
if (g.trackMouseOver) {
this.mainBody.on({
scope: this,
mouseover: this.onRowOver,
mouseout: this.onRowOut
});
}
if (g.enableDragDrop || g.enableDrag) {
this.dragZone = new Ext.grid.GridDragZone(g, {
ddGroup: g.ddGroup || 'GridDD'
});
}
this.updateHeaderSortState();
},


And the render functions:


renderBody: function () {
var cols = [],
i, len = this.cm.getColumnCount(),
col = this.templates.col,
rows = this.renderRows();
if (!rows) {
return '&#160;';
}

return this.templates.body.apply({rows: rows, tstyle: 'width:' + this.getTotalWidth() + ';'});
},
renderHeaders : function()
{
var cm = this.cm,
ts = this.templates,
ct = ts.hcell,
cb = [],
p = {},
len = cm.getColumnCount(),
col = this.templates.col,
last = len - 1;

for (var i = 0; i < len; i++)
{
p.id = cm.getColumnId(i);
p.value = cm.getColumnHeader(i) || '';
p.style = this.getColumnStyle(i, true);
p.tooltip = this.getColumnTooltip(i);
p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');

if (cm.config[i].align == 'right')
{
p.istyle = 'padding-right:16px';
}
else
{
delete p.istyle;
}
cb[cb.length] = ct.apply(p);
}
return ts.header.apply({headers: cb.join('')});
//return ts.header.apply({cells: cb.join(''), tstyle:'width:'+this.getTotalWidth()+';'});
}


Thanks in advance

tobiu
24 Feb 2011, 12:51 AM
user kevin0128 seems to be a bot. he exactly reposted:

http://www.sencha.com/forum/showthread.php?107940-TableGridView-25-50-faster-GridView-implementation&p=511901&viewfull=1#post511901

with 2 spam-links. better block him and remove the posting.


best regards
tobiu

wki01
25 Feb 2011, 2:34 AM
Yes, the DOM structure would allow for width:auto, but the GridView implementation would have to be adapted to get the width of the auto width columns after they have rendered.

I'd like to see this functionality.
You have a little 'time to implement it?
thanks