PDA

View Full Version : TableGridView lightweight GridView based upon a <table>



Animal
18 Aug 2009, 12:35 AM
99.9% of the time when you display a GridPanel, you want the columns autosizing.

The current GridView implementation is massively complex, and based on separate table elements, and so keeping the column widths aligned is a huge overhead, and measuring column widths in one pass in order to then go through and set all column widths is bordering on insane!

IMHO, this is a bad implementation, and the entire Grid's body should just be one <table>

This is faster to render, and automatically sizes column widths. All you have to do is then equalize the column widths between the header cells and row zero of the body table. A simple, one step operation.

The attached file unzips into examples/<any directory>

It displays the array-grid example data using an Ext.ux.TableGridView. I've tested it on FF 3.5, IE 8 and Chrome 3.0.*

This View does not handle any "extras". No column moving or resizing or sorting or hiding.

The eventual idea is that this becomes an Ext.BoxComponent in its own right, not just a slave of a Panel class. Then it could have plugins added for those extra capabilities.

15829

bt_bruno
20 Aug 2009, 8:17 AM
I've always wonder why such a complex structure if a grid is basically a table. Great job =D> Hope to find it on next Ext version.

Animal
20 Aug 2009, 11:00 PM
It's just quick fix because we have a system with a legacy backend which is not a database, does not support paging, and returns a large grid. The performance with the standard GridView was not quick enough so I cobbled this together.

I think a fully functioning GridView with expansion row, moveable, resizable columns could be created from it.

Animal
21 Aug 2009, 12:27 PM
Latest update supports column resizing.

It uses a nice utility class, the Ext.ux.EventZone which creates a mouse event source on an area of an element.

So for instance in the rightmost 5 pixels of a header cell. This then fires mouseenter, mouseleave, mousedown, mousemove, mouseup and click. But only from within its defined subarea of its element.

This is also used to resize the now framed GridPanel. A Ext.ux.EventZone is created based on the lower right 7 pixel square of the GridPanel's outer Element.

No extra resize handle elements needed.

This technique could be usefully used resizing images and input fields where you cannot insert handle elements, and the Ext.Resizable class has to wrap your original with an extra DIV into which it inserts handles.

With this utility class, handles are just zones of the resizable element.

(Note that column resizing does not work in Chrome, and I can't work out why. It works in IE (in standards mode) and FF fine)

rhowardjr
1 Sep 2009, 4:49 PM
Very nicely done!! I seem to hit a small bug.
When I turn frame: false the stripedRows: true doesn't work. I turn frame: true and it works fine. I even tried doing .x-grid3-row-alt to my own background color and no change.


Ext.onReady(function(){

Ext.state.Manager.setProvider(new Ext.state.CookieProvider());

var myData = [
['1','this is a test of the broadcating system.'],
['2','this is a test of the broadcating system.'],
['3','this is a test of the broadcating system.'],
['4','this is a test of the broadcating system.']
];

// example of custom renderer function
function change(val){
if(val > 0){
return '<span style="color:green;">' + val + '</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '</span>';
}
return val;
}

// example of custom renderer function
function pctChange(val){
if(val > 0){
return '<span style="color:green;">' + val + '%</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}

// create the data store
var store = new Ext.data.SimpleStore({
fields: [
{name: 'number'},
{name: 'question'}
]
});
store.loadData(myData);

// create the Grid
window.grid = new Ext.grid.GridPanel({
frame: false,
stateful: false,
view: new Ext.ux.TableGridView({
emptyText: 'Tough! No data!'
}),
store: store,
columns: [
{id:'number',header: "#", width: 16, sortable: true, dataIndex: 'number'},
{header: "Question", width: 180, sortable: true, dataIndex: 'question'}
],
stripeRows: true,
width:243
});

grid.render('grid-example');

//grid.getSelectionModel().selectFirstRow();
});

dbassett74
7 Sep 2009, 6:56 PM
I always wondered why the GridPanel was so complex. Why are rows actually sepeperate tables? Can't the very same functioning grid be created with a single table? Are there any plans to completely re-engineer the GridPanel in a future release to use a single table, but provide same functionality?

rtikku
12 Sep 2009, 1:16 AM
Great job, Animal. We really need something like this.

Found one minor problem, on Chrome 2.0 header and body columns are initially aligned properly. However, where I start resizing them a few time, they start loosing their alignment.

Rakesh

dbassett74
12 Sep 2009, 6:43 AM
I'll ask again since my reply has been ignored thus far.

Is there any reason why the GridPanel has to use individual tables for each row? This REALLY hurts performance. We need a grid that can easily handle thousands of items, and the GridPanel, as nice and fully functional as it is, falls flat on its face with many rows.

Is there any chance at streamlining the GridPanel to use a single table and rows? Yahoo! does it... Do we give up any functionality by going to this single table model??

tonedeaf
12 Sep 2009, 9:54 AM
I'll ask again since my reply has been ignored thus far.

Is there any reason why the GridPanel has to use individual tables for each row? This REALLY hurts performance. We need a grid that can easily handle thousands of items, and the GridPanel, as nice and fully functional as it is, falls flat on its face with many rows.

Is there any chance at streamlining the GridPanel to use a single table and rows? Yahoo! does it... Do we give up any functionality by going to this single table model??
I think individual rows are in their own tables to support grouping. A grouping row with a single column can nest the related rows and expand collapse them easily. Other UI libraries (Activewidgets) don't support grouping by default and its very difficult to create grouped rows probably due to their single table design.

dbassett74
13 Sep 2009, 6:16 AM
Ah, okay, its the grouping that requires the use of tables for each row. I still think that with some ingenuity, we could still come up with a better model. Like maybe when not grouping, it uses a single table model. When grouping, it switches to a model that can better support grouping, even if overall performance suffers a bit. I think it is reasonable to expect an impact on performance when grouping, but when not grouping, why should we still have to suffer the performance impact of individual tables for each row?

tonedeaf
13 Sep 2009, 6:45 AM
I think it is reasonable to expect an impact on performance when grouping, but when not grouping, why should we still have to suffer the performance impact of individual tables for each row?
I agree, I would also say that even if the grid is using GroupingView, it should use a single table design when the grid is not grouped.

Apart from the performance and auto resizing, splitting each row into its own table makes it difficult to browse a table column-wise (like writing a plugin to calculate the height of each row to freeze / unfreeze columns). And there are other cases, where multiple table design heavily impacts performance when building extensions for Ext Grids.

All said, I still like the Ext grid grouping features and wouldn't use the library without them (it was the sole reason why I switched to ExtJS from ActiveWidgets).

vinepod
16 Sep 2009, 9:30 AM
Manimal,

We are generally happy with extjs -- except for grid performance.

We love the lightness and the feel of the TableGridView interface.

We swapped out the SimpleStore, and replaced it with the following - some minor modifications to the grid column dataIndex names are required to get this running, but any php result set should suffice:


var store = new Ext.data.Store({
proxy : new Ext.data.HttpProxy(
{
url : "PNLCompile.php",
method : "POST"
}),

baseParams :
{
action : 'load-pnl-bonds',
accountid : 'xxxxx',
pnldate : '2009-06-30'
},

reader : new Ext.data.JsonReader(
{
fields :
[
{ name : 'rownum' }, // have to add this in or the export to csv doesn't work correctly - securityname is just the row numbers
{ name : "securityname", mapping : "securityname" },
{ name : "type", mapping : "type" },
{ name : "maturity", mapping : "maturity", type:'date' },
{ name : "currency", mapping : "currency" },
]
}),
});

store.load();

When i use an Ext.data.Store with url/params/etc. and load the data store, the following happens:

1. the grid gets populated with data
2. the headers are not aligned with the body of the grid
3. firebug shows


row is undefined
for (var c = 0; c < row.cells.length; c++) { [TableGridView.js (line 749)]



r is undefined
var r = o.records, t = o.totalRecords || r.length; [ext-all-debug.js (line 31750)]


A) the second error message is obviously a by-product of the first.
B) the header mis-alignment is also probably due to the first error.

I think the underlying TableGridView is not somehow understanding the data store records (?)

Any suggestions would be appreciated..

btw: i like the new avatar better than the doc!

fermo111
13 Oct 2009, 7:35 AM
The example included with the .ZIP has a 'sortable' property defined for the columns, but it does not seem to work.


columns: [
{id:'company',header: "Company", width: 160, sortable: true, dataIndex: 'company'},
...
],

In your first post you said that this is not implemented. Do you have any plan to add it in the near future? That would be very useful.

Thanks a lot.

Luca

grzegorz.borkowski
15 Oct 2009, 1:23 PM
Animal, why you say it is necessary to have separate tables for header and body? Is it only to have vertical scroll bar on the body, or perhaps there are other reasons? Regarding vertical scroll bar, from what I know, some browsers support CSS overflow on tbody element. So in the browser that supports it, the grid could probably render as a single table, with separate thead and tbody elements. On the browser without such capability (IE I guess) two tables are probably necessary.
Any chance to have this component in Ext 3.1? At this moment we have the "heavy" grid, and the ultralightweight version DataView. The former is fantastic in terms of functionality, but poor in terms of performance. The second is exactly opposite: it's too simple in many cases. Your solution has a chance to be the right balance between those two, so it would be really good to have in in Ext out of the box.
BTW: perhaps this approach could also fix the longstanding and very annoying problem of text selection in grids, which reduces the grids usability seriously?

Animal
15 Oct 2009, 9:41 PM
You want the header row to sit still while you scroll vertically.

What annoying problem? selectability is under your control (Obviously... you have the source code)

grzegorz.borkowski
15 Oct 2009, 11:55 PM
You want the header row to sit still while you scroll vertically.
Exactly. So in some browsers (at least I've seen it working on FF) you can apply "overflow: auto" to the tbody element, and you have the header row fixed, without using two separate tables. Not sure about other browsers. But taking into account FF popularity and its not-that-blazing-fast performance, making some improvements only for FF makes sense, IMHO.


What annoying problem? selectability is under your control (Obviously... you have the source code)
The fact that you can't select the text in the grid (not editor grid, but simple read-only grid) is extremely annoying and reduces grid's usability - in normal HTML table you can select the text. There were many threads started on Ext forum claiming that this should be not the default bahavior. There are some tricks how to make it working, but for me it never worked smoothly, like in normal HTML table. I suppose that is may be caused by the fact that grid is not a table, but a big, complicated set of tables.

Animal
16 Oct 2009, 12:05 AM
You can take out the unselectable call if you like.

grzegorz.borkowski
16 Oct 2009, 12:49 AM
You can take out the unselectable call if you like.
I'm not sure what you mean... :-?
What I was referring to, is for example this: http://www.extjs.com/forum/showthread.php?p=154426#post154426

Animal
16 Oct 2009, 1:15 AM
It's just HTML. If you can select it with the mouse and copy, and it gets what you want, then that's great.

grzegorz.borkowski
16 Oct 2009, 1:24 AM
That's the point. It would be great, if you could. But you can't. Check the grids section in Ext samples - you are not able to select any text with mouse there: neither cells nor rows, nor a single character is selectable (at least on Firefox). This is not 99% of users expect.

grzegorz.borkowski
16 Oct 2009, 1:26 AM
http://www.extjs.com/deploy/dev/examples/grid/from-markup.html - this one is a perfect example; you have a simple html table, you can select text inside it. Then click the button to generate grid from it - and you will not be able to select the text any more.

tonedeaf
16 Oct 2009, 4:29 AM
Making the text selectable is easy in ExtJS grids. You just have to specify two CSS properties. Check out this post. I assume the same solution will apply for Animal's single table grid?

http://www.extjs.com/forum/showthread.php?p=371191#post371191

Chris_S
16 Oct 2009, 2:09 PM
Animal,

I always find myself having to deal with large amounts of tabular data so this is a subject I am very interested in, thank you for your contribution. I've been trying to weigh the pros and cons between trying to streamline the grid and building up ListViews that look and behave more like my grid implementations. I'm sure that using the ListView must have entered your mind, what made you settle on the table instead?

-Chris

Animal
16 Oct 2009, 2:48 PM
Column sizing.

And tabular data should be displayed in a table. Stands to reason.

Artur Bodera (Joust)
21 Oct 2009, 12:26 AM
Animal,

I always find myself having to deal with large amounts of tabular data so this is a subject I am very interested in, thank you for your contribution. I've been trying to weigh the pros and cons between trying to streamline the grid and building up ListViews that look and behave more like my grid implementations. I'm sure that using the ListView must have entered your mind, what made you settle on the table instead?

-Chris

I have had bad experience with ListViews (http://www.extjs.com/deploy/dev/examples/view/list-view.html)(3.0). Despite it's purpose stated in the manual, they markup is bloated... or rather just plain wrong. It uses floating containers that stack to the left. It doesn't require complex analysis to figure out that the browser has to perform extra calculations to lay them out.

The effect is clearly visible when scrolling down/up the page with listviews inside. Their content will shake, overlap and dance around as the browser tries to keep up with your scrolling. It would never happen with containers of block or table-cell layout.

I have no idea how you came up with DL > DT > EM markup but it's plain wrong. There was a time that it was a good manner to substitute <table> with anything else, but now the extra markup doesn't matter if it's generated on-the-fly with JS. You've created a "high-performance" JS to create a ListView that renders poorly :-)

woomboom
22 Oct 2009, 10:33 PM
Animal,

Seems there is an issue with TableGridView rendering when the store has not loaded its data yet but am not certain without further testing.

I am getting a row.cells not defined error found in the autoSize() function. It is happening at the following line
for (var c = 0; c < row.cells.length; c++) {

I also noticed while looking at the autoSize function that row is defined as a global variable but is not the cause of this error.



// Equalize the automatic widths of each column to the widest.
row = this.getRows()[0];

cdomigan
28 Oct 2009, 3:14 PM
I'm getting the same issue as WoomBoom.

Am looking forward to being able to use this extension!!

tsorgie
5 Dec 2009, 11:55 AM
This is quite awesome work. Any chance of porting it to GXT? I posted on the GXT forum requesting this very same thing.

http://www.extjs.com/forum/showthread.php?t=73011

elkidos
21 Dec 2009, 10:46 PM
@Animal, any plans to integrate that grid with the current official one? Or do you know if dev team is planning to integrate it?

We don't need a huge grid when just rendering simple rows (no grouping). The ListView isn't the solution. The grid must render one <tr> per row, not one <table>..

Animal
22 Dec 2009, 8:51 AM
I doubt it. The dev team have enough on their plate without rewriting one of the central UI classes. Much as I think it should be done, I'm just another customer at the end of the day.

durlabh
22 Dec 2009, 8:52 AM
I read one reply regarding TreeGrid that they are planning 2 table/ grid approach. So, probably next release!

grzegorz.borkowski
3 Feb 2010, 9:01 AM
I've tried to create the single-table based version of this code that would work on firefox, taking advantage of firefox ability to natively apply scroller on <tbody> element. It is possible to do it, but there was one problem with this approach. Ext grids contains table which don't always occupy the whole width of the grid panel. Sometimes the columns are narrow enough, and the panel is wider, so after the last column you have empty space - in such a case the scroll bar is rendered at the right border of the panel, not at the last column. However, I wasn't able to get the same behavior using single table - it looks like firefox assumes that table body can't be wider than sum of table columns (well, it's quite logical, but Ext grids apply different philosophy). So I always ended with scrollbar rendered at the border of the last column, which doesn't look good when grid panel is wider than its columns. I'm not CSS expert, so I can't say it can't be done somehow, but at least I wasn't able to do it. The only workaround I've found is to add one invisible column at the end of the grid, but I dont' like this solution. Besides, we would have to have a bit different HTML structure for grids rendered under firefox (using single table) and other browsers (using one table for grid header and one for grid body), which adds additional complication - not that big deal, but it can cause some problems. So perhaps the cost of implementing single-table version of grid only for firefox can be too high, and the gain is not that big - after all, column size recalculation is done not that often.

Regarding my previous comments - I checked that Animal's lightweight grid is much more text selection friendly - now after fixing some CSS and HTML I'm able to easily select any part of text in grid, which is fantastic comparing to current ext grids, in which selecting a text even after fixing CSS is very hard (though I still believe there should be "textSelectable" configuration option for grids, and I should't be forced to hack with CSS and overrides - it can be set to false by default for backward compatibility).

After looking into this, I think that the current Ext approach with grid and data view is wrong: IMHO, both of them should be replaced with one lightweight component. The component can be quite simple - like the one provided by Animal. All other functionality should be provided by plugins. So the DataView could be replaced directly by this new basic grid; and the classic "thick" grid would be just the same basic lightweight grid with some plugins added: plugin for column resizing, for column reordering, hiding, sorting, etc. That's I think more or less what Animal suggested at the beginning of this thread. I hope durlabh is right and it will happen with 3.2 release - does anybody have some news about it?

Stju
9 Jun 2010, 3:53 PM
row is undefined
for (var c = 0; c < row.cells.length; c++) { [TableGridView.js (line 749)]
Does anyone found a solution?

wki01
9 Sep 2010, 5:21 AM
row is undefined
for (var c = 0; c < row.cells.length; c++) { [TableGridView.js (line 749)]Does anyone found a solution?

I have the same problem using this plugin in this example:
http://www.sencha.com/forum/showthread.php?76406-jsonStore-gt-panel.items&p=371353#post371353

There are no solutions?

thanks

radtad
19 Oct 2010, 5:02 PM
Animal,

How easy would this be to add a GroupingView and / or extending this to use an EditorGridPanel? Will this play friendly with the two?

Condor
19 Oct 2010, 11:03 PM
My TableGridView (http://www.sencha.com/forum/showthread.php?107940-TableGridView-25-50-faster-GridView-implementation) can already be used in an EditorGridPanel.

However, creating a TableGroupingView would require a lot more work.

wki01
25 Oct 2010, 4:45 AM
Hello Animal

my test code:
I am using ext 3.30



Ext.onReady(function(){

var recordFields = [ //1
{ name : 'id', mapping : 'id' },
{ name : 'firstname', mapping : 'firstname' },
{ name : 'lastname', mapping : 'lastname' },
{ name : 'street', mapping : 'street' },
{ name : 'city', mapping : 'city' },
{ name : 'state', mapping : 'state' },
{ name : 'zip', mapping : 'zip' },
{ name : 'country', mapping : 'country' }
];

var store = new Ext.data.JsonStore({
fields : recordFields,
url : 'http://tdg-i.com/dataQuery.php',
totalProperty : 'totalCount',
root : 'records',
autoLoad : false,
remoteSort : false
});

// create the Grid
grid = new Ext.grid.GridPanel({
frame: true,
stateful: false,
store: store,
columns: [
{id:'firstname',header: "firstname", sortable: true, dataIndex: 'firstname'},
{id:'lastname',header: "lastname", sortable: true, dataIndex: 'lastname'}
],
view: new Ext.ux.TableGridView({
emptyText: 'Tough! No data!'
}),
bbar: new Ext.PagingToolbar({
store: store,
pageSize: 20,
displayInfo: true,
displayMsg: '{0}-{1} di {2}',
emptyMsg: ""
}),
stripeRows: true,
height:350,
width:600,
title:'Array Grid'
});
grid.on({
render: {scope:this, fn:function() {
store.load.defer(100, store, [{params:{start: 0, limit: 20}}])
}}
});

grid.render('grid-example');

grid.getSelectionModel().selectFirstRow();
});
I get the following error:

row.cells is null or not an object line 749 in TableGridView.js

thanks