在ExtJS 4.1 beta 2中,我设法通过远程存储实现了无限滚动网格。我基本上采用了一个现有的(完全可操作的)分页网格(具有远程存储,过滤和排序功能),然后放入适当的配置以进行无限滚动:
// Use a PagingGridScroller (this is interchangeable with a PagingToolbar)
verticalScrollerType: 'paginggridscroller',
// do not reset the scrollbar when the view refreshs
invalidateScrollerOnRefresh: false,
// infinite scrolling does not support selection
disableSelection: true,
[docs中的任何地方都没有说这个(请参阅无限滚动部分),但是您需要将商店设置为具有buffered: true
配置。而且您无法使用store.load()
进行加载,需要这样做:
store.prefetch({
start: 0,
limit: 200,
callback: function() {
store.guaranteeRange(0, 99);
}
});
[所有这些,如果我缓慢滚动并因此允许数据预取,不要使用任何过滤器,也不要使用任何排序,那么一切都会很好。
但是,如果我快速滚动或尝试在激活过滤器的情况下使无限滚动网格重新加载,或者在排序时,它们都会破裂。错误是options is undefined
。
我花了几个小时在代码中进行了一些跟踪和谷歌搜索,除了得出结论,没有人使用远程过滤器和远程滚动实现无限滚动网格,我发现了以下内容:
由于Ext.data.Store
中的此方法导致过滤器崩溃,当需要从服务器获取更多数据时,无限滚动器会调用此方法:
mask: function() {
this.masked = true;
this.fireEvent('beforeload');
},
由于某种原因,此方法会触发beforeload
事件无 Ext.data.Operation
参数,该参数应该是指定的here的一部分。
结果,由于未定义“选项”,因此在onbeforeload
的Ext.ux.grid.FiltersFeature
处理程序中发生错误:
/**
* @private
* Handler for store's beforeload event when configured for remote filtering
* @param {Object} store
* @param {Object} options
*/
onBeforeLoad : function (store, options) {
options.params = options.params || {};
this.cleanParams(options.params);
var params = this.buildQuery(this.getFilterData());
Ext.apply(options.params, params);
},
我可以从PagingScroller代码中删除对此mask
方法的调用,然后滚动功能很棒。我可以根据需要快速滚动,并且可以正确加载数据。 但是然后过滤器和排序不会应用于ajax请求。
我还没有深入研究排序方面,但是我认为它与mask
方法类似,因为sort只是operation
对象包含的另一个元素,它导致no操作对象成为传递给ajax请求。
[我在想,如果我能弄清楚如何用mask
参数强制beforeload
方法触发operation
(就像文档所说的那样),一切都会好的。问题是,我无法弄清楚该怎么做。有什么建议吗?
[如果有人只是告诉我我错了,而实际上人们已经做了这项工作,我会受到鼓舞,但是您用来处理此问题或链接的任何替代代码的片段将不胜感激。
我也尝试降级到4.0.7和4.0.2a,并且得到相同的结果,所以这不仅仅是一个beta问题。
更新-2012年2月7日:
这似乎实际上可能是Ext.ux.grid.FilterFeature
问题,而不是无限滚动问题。如果我删除FilterFeature配置,则完全无限滚动效果很好,并且在按列排序时确实会将排序参数传递给我的后端。我将开始研究FilterFeature的结尾。
SUCCESS!我可以使用远程过滤器和远程排序进行无限滚动(这是在4.1 beta 2中进行的,但是由于在4.02a和4.0.7中遇到相同的错误,我想它可以解决这些问题太)。基本上,我只需要在代码中添加一些替代。
我还没有在其他浏览器中进行过测试,但是已经在FF中进行了测试。这是我正在使用的替代:
Ext.override(Ext.data.Store, {
// Handle prefetch when all the data is there and add purging
prefetchPage: function(page, options, forceLoad) {
var me = this,
pageSize = me.pageSize || 25,
start = (page - 1) * me.pageSize,
end = start + pageSize;
// A good time to remove records greater than cache
me.purgeRecords();
// No more data to prefetch
if (me.getCount() === me.getTotalCount() && !forceLoad) {
return;
}
// Currently not requesting this page and range isn't already satisified
if (Ext.Array.indexOf(me.pagesRequested, page) === -1 && !me.rangeSatisfied(start, end)) {
me.pagesRequested.push(page);
// Copy options into a new object so as not to mutate passed in objects
options = Ext.apply({
page : page,
start : start,
limit : pageSize,
callback : me.onWaitForGuarantee,
scope : me
}, options);
me.prefetch(options);
}
},
// Fixes too big guaranteedEnd and forces load even if all data is there
doSort: function() {
var me = this;
if (me.buffered) {
me.prefetchData.clear();
me.prefetchPage(1, {
callback: function(records, operation, success) {
if (success) {
guaranteeRange = records.length < 100 ? records.length : 100
me.guaranteedStart = 0;
me.guaranteedEnd = 99; // should be more dynamic
me.loadRecords(Ext.Array.slice(records, 0, guaranteeRange));
me.unmask();
}
}
}, true);
me.mask();
}
}
});
Ext.override(Ext.ux.grid.FiltersFeature, {
onBeforeLoad: Ext.emptyFn,
// Appends the filter params, fixes too big guaranteedEnd and forces load even if all data is there
reload: function() {
var me = this,
grid = me.getGridPanel(),
filters = grid.filters.getFilterData(),
store = me.view.getStore(),
proxy = store.getProxy();
store.prefetchData.clear();
proxy.extraParams = this.buildQuery(filters);
store.prefetchPage(1, {
callback: function(records, operation, success) {
if (success) {
guaranteeRange = records.length < 100 ? records.length : 100;
store.guaranteedStart = 0;
store.guaranteedEnd = 99; // should be more dynamic
store.loadRecords(Ext.Array.slice(records, 0, guaranteeRange));
store.unmask();
}
}
}, true);
store.mask();
}
});
我的商店的配置如下:
// the paged store of account data
var store = Ext.create('Ext.data.Store', {
model: 'Account',
remoteSort: true,
buffered: true,
proxy: {
type: 'ajax',
url: '../list?name=accounts', //<-- supports remote filter and remote sort
simpleSortMode: true,
reader: {
type: 'json',
root: 'rows',
totalProperty: 'total'
}
},
pageSize: 200
});
网格为:
// the infinite scroll grid with filters
var grid = Ext.create('Ext.grid.Panel', {
store: store,
viewConfig: {
trackOver: false,
singleSelect: true,
},
features: [{
ftype: 'filters',
updateBuffer: 1000 // trigger load after a 1 second timer
}],
verticalScrollerType: 'paginggridscroller',
invalidateScrollerOnRefresh: false,
// grid columns
columns: [columns...],
});
此外,初始加载也必须像这样完成(不仅仅是store.load():
store.prefetch({
start: 0,
limit: 200,
callback: function() {
store.guaranteeRange(0, 99);
}
});
您的答案提供了正确的方向,我从中修改了您的代码
store.loadRecords(Ext.Array.slice(records, 0, count));
to
store.loadRecords(Ext.Array.slice(records, 0, records.length));
这解决了您以前的过滤器返回空结果的问题。插入此更改后,它可以正常工作。