PDA

View Full Version : TabPanel rendering infinite Grid too quickly.



incutonez
16 Dec 2013, 2:51 PM
Let's say I have a TabPanel that gets two components added to it. Each component contains an Infinite Grid. Each Infinite Grid loads its data from a service call, and each set of data contains 2,000 records. After the components are added to the TabPanel, we set each one to be the active tab, using setActiveTab. We first set the 2nd tab as the active tab and then set the first tab. When the page loads, the first tab is selected, as we expected.

When looking at the first tab, everything looks fine... we can infinitely scroll, sort, hide columns, etc. However, if we switch to the second tab, we see that it has partially loaded, and we can't scroll, hide columns, sort, etc. It's almost as if using setActiveTab was a bit premature with rendering the grid... as if the store wasn't completely loaded, but the tab was rendered anyway. (this is what I'm assuming is the issue)

I do have code, but it takes a little work on your end to reproduce (because you need a service call). I'm using CompoundJS within a Node.js application, so it was very easy for me to create the test case. If you have access to a database, and can make a quick service call, just modify my Ext JS code, but if you want to use Node.js, you can try this:

Ext JS 4.2.1


Ext.onReady(function() {
var tabPanel = Ext.create('Ext.tab.Panel', {
width: 400,
height: 400,
renderTo: Ext.getBody()
});

Ext.define('myGrid', {
extend: 'Ext.grid.Panel',
constructor: function(config) {
this.columns = config.columns;
this.store = Ext.create('Ext.data.Store', {
fields: config.fields,
buffered: true,
leadingBufferZone: 20,
pageSize: 50,
proxy: {
type: 'ajax',
url: '/getData?id=' + config.id,
reader: {
totalProperty: 'totalCount',
type: 'json',
root: 'root'
}
},
autoLoad: true
});
this.id = config.id;
this.callParent();
}
});

var grid1 = Ext.create('myGrid', {
id: 'blah',
columns: [{
text: 'one',
dataIndex: 'one'
}, {
text: 'two',
dataIndex: 'two'
}, {
text: 'three',
dataIndex: 'three'
}],
fields: ['one', 'two', 'three'],
title: 'grid1'
});

var grid2 = Ext.create('myGrid', {
id: 'bleh',
columns: [{
text: 'one',
dataIndex: 'one'
}, {
text: 'two',
dataIndex: 'two'
}, {
text: 'three',
dataIndex: 'three'
}],
fields: ['one', 'two', 'three'],
title: 'grid2'
});

var c1 = [];
c1.items = [grid1];
c1.title = "BLAH";
c1.layout = 'fit';
var c2 = [];
c2.items = [grid2];
c2.title = "BLEH";
c2.layout = "fit";
tabPanel.add([c1, c2]);
tabPanel.setActiveTab(1);
tabPanel.setActiveTab(0);
});


Node.js code


compound init test && cd test
npm install
compound g s testcontroller


Replace app/controllers/testcontrollers_controller.js with:



load('application');

action('getData', function(data) {
var query = data.req.query;
var id = query.id;
var page = query.page;
var pushObj;
if (id === 'blah') {
pushObj = {
one: 'bye',
two: 'goodbye',
three: 'auf wiedersehen'
};
}
else {
pushObj = {
one: 'hi',
two: 'hello',
three: 'guten tag'
};
}
var obj = [];
for (var i = 0; i < 50; i++) {
obj.push(pushObj);
}
send({
totalCount: 2000,
root: obj,
page: page
});
});


In config/routes.js, remove testcontroller's map.resources line, and add this:



map.get('getData', 'testcontrollers#getData');


In public/index.html, make it a generic HTML file, and add in your links to Ext JS and my above Ext JS code.

Now, once you've done all of that, you should be able to reproduce my issue. The first tab will open and be just fine, but the second tab only loads the first x amount of records and doesn't function properly. I believe this is due to the store not loading completely when setActiveTab is fired, which makes the rendering load an impartial store.

What I want to know is, how do I get this to properly work? I've tried waiting for the store to load, and then adding it to the tab, but that still gives me some strange results. I've also tried waiting for the grid to stop rendering, but still, I get inconsistent results... sometimes the grid loads all the way, and the tab is fine, other times, I get a cannot read property 'length' of undefined in ext-all-dev.js:135,786... which makes it seem like the store hasn't completely loaded, as that line refers to records.length.

If anyone has any ideas, I'd love to hear them!

incutonez
17 Dec 2013, 10:17 AM
I was able to reproduce the problem in this Sencha Fiddle example (https://fiddle.sencha.com/#fiddle/28i). You may have to run the code a few times to get the issue, but Firebug should be reporting the length of undefined error I explained above.

incutonez
18 Dec 2013, 9:20 AM
Thanks to rixo over on StackOverflow (http://stackoverflow.com/questions/20636777/ext-js-tabpanel-rendering-infinite-grid-too-quickly#answer-20654251), he provided a working solution, and it looks like it might be a bug in the BufferedRenderer, so I will create a bug in that forum. The solution is as follows:



/* Prevents BufferedRenderer plugin to break when buffered views are
* rendered or refreshed while hidden, like in a card layout.
* Tested with Ext 4.2.1 */
Ext.define('Modules.SafeHouseModule.view.components.HiddenRenderingSupport', {
override: 'Ext.grid.plugin.BufferedRenderer',

/**
* Refreshes the view and row size caches if they have a value of 0
* (meaning they have probably been cached when the view was not visible).
*/
onViewResize: function() {
if (this.rowHeight === 0) {
if (this.view.body.getHeight() > 0) {
this.view.refresh();
}
}
else {
this.callParent(arguments);
}
}
});

Gary Schlosberg
18 Dec 2013, 10:17 AM
Your Fiddle example doesn't load for me in Firefox or Chrome, but we should continue this discussion on the bug thread:
http://www.sencha.com/forum/showthread.php?278765