PDA

View Full Version : Problems with Infinite Scroller



LisburnLad
20 Jan 2012, 2:33 PM
I'm having a few problems getting the Infinite Scroller to work (using the 4.1 Beta). I'm not sure if these problems are caused by the way I've set things up, or if they're problems in the Infinite Scroller itself.

The test code I'm using is a modified version of the Infinite Scroller from the examples:



<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="Lib/ExtJS/resources/css/ext-all.css"/>
<script type="text/javascript" src="Lib/ExtJS/ext-all-debug.js"></script>

<script type="text/javascript">

Ext.Loader.setConfig({ enabled: true });

Ext.Loader.setPath('Ext.ux', '../ux/');
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.grid.PagingScroller'
]);

Ext.onReady(function ()
{
Ext.define('RatingModel',
{
extend: 'Ext.data.Model',
fields: [
'rating',
'ratingId',
'userId'
],
idProperty: 'ratingId'
});

// create the Data Store
var store = Ext.create('Ext.data.Store',
{
id: 'store',
//pageSize: 10,
model: 'RatingModel',
buffered: true,
proxy:
{
type: 'ajax',
url: 'ReviewLoader.aspx',
reader:
{
type: 'json',
root: 'rows',
totalProperty: 'totalCount'
},
extraParams:
{
itemID: '1',
categoryID: '13773'
}
, simpleSortMode: true
},
sorters: [{ property: 'rating', direction: 'ASC'}]
});


var grid = Ext.create('Ext.grid.Panel',
{
width: 700,
height: 260,
store: store,
verticalScrollerType: 'paginggridscroller',
loadMask: true,
disableSelection: true,
invalidateScrollerOnRefresh: false,
viewConfig:
{
trackOver: false
},

dockedItems: [
{
xtype: 'toolbar',
dock: 'top',
items:
[{
xtype: 'button',
text: 'load',
handler: function ()
{
store.removeAll(true);
var totalCount = store.getTotalCount();

store.proxy.extraParams.itemID = '2';
store.proxy.extraParams.categoryID = '13773';

store.prefetch(
{
start: 0,
limit: 29,
callback: function ()
{
store.guaranteeRange(0, 9);
}
})
}
}]
}],

columns:
[{
id: 'ratingId',
header: "ID",
dataIndex: 'ratingId',
width: 90
},
{
id: 'author',
header: "Author",
dataIndex: 'userId',
flex: 1
},
{
id: 'rating',
header: "Rating",
dataIndex: 'rating',
width: 90
}],
renderTo: Ext.getBody()
});


/* Debug code to instrument the scroll gestures on the buffered grid.*/
grid.view.on({
scroll: updateGridData,
element: 'el'
})
store.on({
load: updateGridData,
datachanged: updateGridData
})
var pg = Ext.create('Ext.grid.property.Grid', {
style: {
position: 'absolute'
},
x: 735,
y: 0,
width: 500,
width: 300,
height: 230,
source: getProperties(),
renderTo: document.body
});
function updateGridData()
{
pg.setSource(getProperties());
}
function getProperties()
{
var t = grid.view.el.child('table', true);
return {
"Store Total count": store.getTotalCount(),
"Store count": store.getCount(),
"Table size": grid.view.el.query('tr').length,
"Guaranteed start": store.guaranteedStart,
"Guaranteed end": store.guaranteedEnd,
"Prefetch start": store.prefetchData.items.length ? store.prefetchData.items[0].index : 'none',
"Prefetch end": store.prefetchData.items.length ? store.prefetchData.items[store.prefetchData.items.length - 1].index : 'none',
"View scrollTop": grid.view.el.dom.scrollTop,
"Table top position": t ? t.style.top : ''
};
}

// Load a maximum of 30 records into the prefetch buffer (which is NOT mapped to the UI)
// When that has completed, instruct the Store to load the first page from prefetch into the live, mapped record cache
store.prefetch({
start: 0,
limit: 29,
callback: function ()
{
store.guaranteeRange(0, 9);
}
});
});

</script>
</head>
<body>
</body>
</html>



At the backend I've got a simple ASP page that returns the following block of JSON when the supplied itemID is 1 (when the page first loads):


"{'totalCount':'12', 'rows':[{'rating':'4','ratingId':'1','userId':'Administrator'},
{'rating':'2','ratingId':'2','userId':'Joey Mang'},
{'rating':'1','ratingId':'3','userId':'Test0'},
{'rating':'1','ratingId':'4','userId':'Test0'},
{'rating':'1','ratingId':'5','userId':'Test0'},
{'rating':'3.5','ratingId':'6','userId':'Test1'},
{'rating':'2.5','ratingId':'7','userId':'Test2'},
{'rating':'4','ratingId':'8','userId':'Test3'},
{'rating':'5','ratingId':'9','userId':'Test4'},
{'rating':'4.5','ratingId':'10','userId':'Test5'},
{'rating':'2.5','ratingId':'11','userId':'Test6'},
{'rating':'2.5','ratingId':'12','userId':'Test7'}]}"

And this block of JSON when the load button is clicked:


"{'totalCount':'20', 'rows':[{'rating':'4','ratingId':'20','userId':'Cheese'},
{'rating':'4','ratingId':'21','userId':'Cheese'},
{'rating':'2','ratingId':'22','userId':'Cheese'},
{'rating':'1','ratingId':'23','userId':'Cheese0'},
{'rating':'1','ratingId':'24','userId':'Cheese0'},
{'rating':'1','ratingId':'25','userId':'Cheese0'},
{'rating':'3.5','ratingId':'26','userId':'Cheese1'},
{'rating':'2.5','ratingId':'27','userId':'Cheese2'},
{'rating':'4','ratingId':'28','userId':'Cheese3'},
{'rating':'5','ratingId':'29','userId':'Cheese4'},
{'rating':'4.5','ratingId':'30','userId':'Cheese5'},
{'rating':'4','ratingId':'31','userId':'Cheese'},
{'rating':'3','ratingId':'32','userId':'Cheese'},
{'rating':'1','ratingId':'33','userId':'Cheese0'},
{'rating':'1','ratingId':'34','userId':'Cheese0'},
{'rating':'1','ratingId':'35','userId':'Cheese0'},
{'rating':'3.5','ratingId':'36','userId':'Cheese1'},
{'rating':'3.5','ratingId':'37','userId':'Cheese2'},
{'rating':'4','ratingId':'38','userId':'Cheese3'},
{'rating':'5','ratingId':'39','userId':'Cheese4'}]}"


The problems I'm having are as follows:

1. With no page size set in the store, 2 calls are made to the back end when the page first loads. Firebug shows these to have the following parameters:

Call 1:


categoryID
13773


dir
ASC


itemID
1


limit
29


sort
rating


start
0




Call 2:


categoryID
13773


dir
ASC


itemID
1


limit
308


page
1


sort
rating


start
0




Since the first call to preload the data gets the full set of records, I'm not sure why this second call is occurring.
With this setup the page initially displays the first 10 records as expected. However, clicking down on the scroll bar results in a load more calls to the back end (again I'd have thought these shouldn't be happening) and the grid then goes blank. All of these calls have the same set of parameters as the second call shown above.
If instead I uncomment the page size, setting it to a value of 10, I only get a single call to the backend (with the parameters shown in the first call above). In this case when I click on the scroll bar, the loading pacifier appears, but no more calls to the backend occur and the page locks up.

2. The second problem I'm having is to do with the prefetched data seemingly not being cleared by a call to "store.removeAll(true)" (perhaps I should be calling something different?).
Again, with the example above, when the page is first loaded the first set of data is loaded into the grid. If I then click on the load button, a request is made to the backend for the second data set and firebug shows me that this gets returned. However the displayed data doesn't change. When I inspect the store it still contains the prefetched data that was returned from the first set of JSON. How can I clear this data and load the new set?

Any help with these issues would be much appreciated.
Thanks,
Steve

Animal
21 Jan 2012, 1:25 AM
It tries to keep the prefetch buffer a decent size to allow refreshes of the data without going to the server. A page size of 10 won't be enough to keep the prefetch buffer primed. It will attempt to use your configured value, but it won't work. Best to let it use a calculated value.

So it will load more than 29, so that you can start scrolling and it can load the Store from the prefetch buffer very quickly.

If it has the whole dataset, then it should not go back to the server for more.

In fact, what's slow is the DOM. It's creating and rendering a huge HTML <table> that skows things down, not having lots of records in a prefetch buffer.

So you could in fact ask it to prefetch 5000 records in that first statement, and then in the callback, only load 20 records into the Store (You need some records either side of the visible area to allow a little scrolling!).

That would (should!) mean no more requests to the server, and instananeous refreshes of the small <table> every time it gets near to showing the last row.

removeAll should probably clear the prefetch buffer. If it does not, then that's a bug.

LisburnLad
21 Jan 2012, 2:17 AM
Hi Animal,

Thanks for replying. In addition to removeAll not clearing the prefetch buffer, is it also then a bug that further calls have been made to the server once the complete data set has already been returned?

Do you want me to raise bugs for these issues, and if so, would you prefer 2 seperate bugs, or is it ok to put them in together?

Ta,
Steve

LisburnLad
21 Jan 2012, 6:58 AM
I've just raised a couple of bugs for these issues:

For more data being requested after all records have already been returned to the store:

http://www.sencha.com/forum/showthread.php?175777-Infinite-scroll-requests-more-data-after-all-records-have-been-returned


and for the prefetched data not being removed after calling the store's "removeAll":

http://www.sencha.com/forum/showthread.php?175778-4.1Beta-A-call-to-a-store-s-quot-removeAll-quot-function-does-not-remove-any-prefetched-data

LisburnLad
23 Jan 2012, 2:29 PM
Now that the first bug has been fixed, and the infinite scroller is working with the first set of data returned to the store, I'm not sure if the second bug is correct.

It does appear that the store is correctly loaded with the second set of data. However, this data never gets displayed in the grid, which always retains the first set of data, even though this appears to no longer be present in the store.

With the infinite scroller is there some form of caching going on, and if so, how do I clear this and get it to use the new data that's been loaded into the store?