PDA

View Full Version : [FIXED] [4.2] buffered grid mask problems



dvoracekPDS
4 Apr 2013, 3:24 AM
Hello,

I have stumbled upon two issues with buffered grid loading mask in Ext 4.2 build 663 on FF 20

When i scroll into a range not yet in page map, grid store starts loading and loading mask is displayed over the grid...

1. There may be several ajax requests fired (to load also the leading and trailing areas as configured in store). The mask disappears as soon as any of these requests is completed, but if it does not contain the range to be displayed in the current visible grid area, the grid displays empty space until the "right" request completes. This may be confusing for users.

2. If the grid is inside a window component and i move the window while the loading mask of the grid is displayed, the label with the "Loading..." text and animated icon moves with the window but the mask itself stays in it's original position.

*EDIT BY SLEMMON
Issue 1 was reproducable in 4.2 when I loaded a dataset in a buffered store/grid and imposed latency on the requests.
Issue 2 appears to be reported already. Reference:
http://www.sencha.com/forum/showthread.php?252691

slemmon
4 Apr 2013, 7:12 AM
1. There may be several ajax requests fired (to load also the leading and trailing areas as configured in store). The mask disappears as soon as any of these requests is completed, but if it does not contain the range to be displayed in the current visible grid area, the grid displays empty space until the "right" request completes. This may be confusing for users.

Not totally sure I follow. I loaded up the buffered forums example in FF, Chrome, and Safari and didn't see anything that caught my eye as an odd or unwanted behavior.



2. If the grid is inside a window component and i move the window while the loading mask of the grid is displayed, the label with the "Loading..." text and animated icon moves with the window but the mask itself stays in it's original position.


Looks like this issue is reported and input in the bug tracker currently.
But, thank you for taking the time to report it. Much appreciated!
http://www.sencha.com/forum/showthread.php?252691

dvoracekPDS
5 Apr 2013, 4:40 AM
slemmon: Thanks for the response.
ad 1.: I believe the problem lies in LoadMask's implementation of Bindable mixin method getStoreListeners.

When you bind a LoadMask to a store (like the Grid component is doing) the displaying of the LoadMask is handled by store event listeners. The problem is, that the 'load' event is handled the same way as the 'prefetch' event: it hides the mask.

So if i start loading grid content and prefetch of some trailing part of data (not visible in grid area) completes before the actual data to display arrive, the 'prefetch' event is raised and the mask hides, but the grid displays only empty space until the request with the part of the data to display is fetched and finally displayed in the grid.

It depends on ajax latency. Try the Infinite Scroll Grid Tuner example with buffered option checked and high ajax latency setting (like 5000ms) and try several jumps into yet uncached areas of the grid and it's quite noticeable.

If i comment out the line with the prefetch listener, it seems to work fine with my grid, but i'm not sure if it can't cause trouble in some other grid setups or scenarios.


getStoreListeners: function(store) {
var load = this.onLoad,
beforeLoad = this.onBeforeLoad,
result = {
cachemiss: beforeLoad,
cachefilled: load
};

if (!store.proxy.isSynchronous) {
result.beforeLoad = beforeLoad;
result.load = load;
result.prefetch = load; // <==== here :)
}
return result;
},

slemmon
5 Apr 2013, 10:44 AM
I'm with you now. Thanks for the clarifications.

Thanks for the report! I have opened a bug in our bug tracker.

Animal
18 Apr 2013, 11:59 AM
Does this help?



Ext.override(Ext.data.Store, {
getRange: function(start, end, options) {
//<debug>
if (options && options.cb) {
options.callback = options.cb;
Ext.Error.raise({
msg: 'guaranteeRange options.cb is deprecated, use options.callback'
});
}
//</debug>

var me = this,
requiredStart,
requiredEnd,
maxIndex = me.totalCount - 1,
lastRequestStart = me.lastRequestStart,
pageAddHandler,
result;

options = Ext.apply({
prefetchStart: start,
prefetchEnd: end
}, options);

if (me.buffered) {
// Sanity check end point to be within dataset range
end = (end >= me.totalCount) ? maxIndex : end;

// We must wait for a slightly wider range to be cached.
// This is to allow grouping features to peek at the two surrounding records
// when rendering a *range* of records to see whether the start of the range
// really is a group start and the end of the range really is a group end.
requiredStart = start === 0 ? 0 : start - 1;
requiredEnd = end === maxIndex ? end : end + 1;

// Keep track of range we are being asked for so we can track direction of movement through the dataset
me.lastRequestStart = start;

// If data request can be satisfied from the page cache
if (me.rangeCached(requiredStart, requiredEnd)) {
me.onGuaranteedRange(options);
result = me.data.getRange(start, end);

// Load the pages around the requested range required by the leadingBufferZone and trailingBufferZone.
me.primeCache(start, end, start < lastRequestStart ? -1 : 1);
}
// At least some of the requested range needs loading from server
else {
// Private event used by the LoadMask class to perform masking when the range required for rendering is not found in the cache
me.fireEvent('cachemiss', me, start, end);

// Add a pageAdded listener, and as soon as the requested range is loaded, fire the guaranteedrange event
pageAddHandler = function(page, records) {
if (me.rangeCached(requiredStart, requiredEnd)) {
// Private event used by the LoadMask class to unmask when the range required for rendering has been loaded into the cache
me.fireEvent('cachefilled', me, start, end);
me.data.un('pageAdded', pageAddHandler);
me.onGuaranteedRange(options);

// Load the pages around the requested range required by the leadingBufferZone and trailingBufferZone.
me.primeCache(start, end, start < lastRequestStart ? -1 : 1);
}
};
me.data.on('pageAdded', pageAddHandler);

// Prioritize the request for the *exact range that the UI is asking for*.
// When a page request is in flight, it will not be requested again by checking the me.pageRequests hash,
// so the request after this will only request the *remaining* unrequested pages .
me.prefetchRange(start, end);

}
} else {
result = me.data.getRange(start, end);

// Someone *may* use the callback interface to process their results even if the store is not buffered and always synchronous
if (options.callback) {
options.callback.call(options.scope || me, result, start, end, options)
}
}

return result;
}
});

Animal
18 Apr 2013, 12:00 PM
The mask issue is another ticket. It's a difficult one and will not be included in any fix for this ticket.

Animal
19 Apr 2013, 1:43 AM
Yes, it does work without that prefetch listener. The cachefill event will be what clears the mask when the needed pages are in the cache.

I will fix this.