具有远程过滤器和排序的ExtJS无限滚动网格

时间:2012-02-06 06:49:50

标签: javascript javascript-events extjs extjs4 filtering

在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并得到相同的结果,因此它不仅仅是测试版问题。

更新 - 2月7日12日:

这似乎实际上可能是Ext.ux.grid.FilterFeature问题,而不是无限滚动问题。如果我删除FilterFeature配置完全无限滚动工作很好,并在我按列排序时将排序参数传递给我的后端。我将开始研究FilterFeature的结尾。

2 个答案:

答案 0 :(得分:14)

成功!我有无限滚动使用远程过滤器和远程排序(这是在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);
    }
});    

答案 1 :(得分:4)

您的答案提供了正确的方向,我修改了您的代码

store.loadRecords(Ext.Array.slice(records, 0, count));

store.loadRecords(Ext.Array.slice(records, 0, records.length));

这解决了先前过滤器返回空结果的问题。插入此更改后,它正常工作。