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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9156541/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 05:46:51  来源:igfitidea点击:

ExtJS Infinite Scroll Grid with remote Filters and Sort

javascriptextjsextjs4filteringdom-events

提问by vanderwyst

In ExtJS 4.1 beta 2 I managed to implement an infinite scroll grid with a remote store. I basically took an existing (fully operational) paging grid (with remote store, filtering and sorting) and then put in the appropriate configs for infinite scrolling:

在 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,   

It doesn't say this anywhere in the docs(see Infinite Scrolling section), but you need to set your store to have buffered: trueconfig. And you can't load with store.load()it needs to be done like this:

它没有在文档中的任何地方说明这一点(请参阅无限滚动部分),但您需要将商店设置为具有buffered: trueconfig. 你不能加载store.load()它需要这样做:

store.prefetch({
    start: 0,
    limit: 200,
    callback: function() {
        store.guaranteeRange(0, 99);
    }
});   

With all that, everything works great if I scroll slowly and thus allow the data to prefetch, don't use any filters and don't use any sorting.

尽管如此,如果我缓慢滚动并允许数据预取,则一切都很好,不要使用任何过滤器,也不要使用任何排序。

However, if I scroll fast or try to make the infinite scroll grid reload with a filter active or while sorting it all breaks apart. Error is options is undefined.

但是,如果我快速滚动或尝试使用过滤器重新加载无限滚动网格,或者在排序时将其全部分解。错误是options is undefined

I've spent a couple of hours doing some tracing in the code and googling and aside from concluding that no one has implemented an infinite scroll grid with remote filters and remote scrolling, I have found the following:

我花了几个小时在代码和谷歌搜索中进行了一些跟踪,除了得出结论认为没有人实现了带有远程过滤器和远程滚动的无限滚动网格之外,我发现了以下内容:

The filtering is breaking down because of this method in Ext.data.Storewhich is called by the infinite scroller when it needs more data from the server:

由于Ext.data.Store无限滚动器在需要来自服务器的更多数据时调用此方法,因此过滤正在崩溃:

mask: function() {
    this.masked = true;   
    this.fireEvent('beforeload');
},

For some reason, this method fires the beforeloadevent withoutthe Ext.data.Operationparameter which is supposed to be part of it as specified here.

出于某种原因,此方法会在没有参数的情况下触发beforeload事件Ext.data.Operation参数应该是此处指定的一部分。

As a result, an error occurs in the onbeforeloadhandler in Ext.ux.grid.FiltersFeaturebecause of course "options" is undefined:

结果,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);

},

I can cut out the call to this maskmethod from the PagingScroller code and then the scroll functionality is great. I can scroll as fast as I like and it loads the data properly. Butthen filters and sort does not get applied to the ajax requests.

我可以mask从 PagingScroller 代码中删除对这个方法的调用,然后滚动功能很棒。我可以随心所欲地滚动并正确加载数据。但是过滤器和排序不会应用于 ajax 请求。

I haven't dived as much into the sorting aspect but I think it something similar with this maskmethod because sort is simply another element contained by the operationobject and it causes nooperation object to be passed to the ajax request.

我没有深入研究排序方面,但我认为它与此mask方法类似,因为排序只是operation对象包含的另一个元素,它不会导致没有操作对象传递给 ajax 请求。

I'm thinking that if I could just figure out how to force the maskmethod to fire beforeloadwith the operationparameter (like the docs say it is supposed to) everything will be fine. Problem is, I haven't been able to figure out how to do that. Any suggestions?

我在想,如果我能弄清楚如何强制mask方法beforeload使用operation参数触发(就像文档所说的那样),一切都会好起来的。问题是,我一直无法弄清楚如何做到这一点。有什么建议?

If someone would just tell me that I am wrong and people have in fact made this work, I would be inspired, but a snippet of any overrides you used to handle this problem or a link would be much appreciated.

如果有人只是告诉我我错了,而实际上人们已经完成了这项工作,我会受到启发,但是您用来处理此问题的任何覆盖片段或链接将不胜感激。

I've also tried downgrading to 4.0.7 and 4.0.2a and I get the same results, so it isn't just a beta problem.

我也试过降级到 4.0.7 和 4.0.2a,我得到了相同的结果,所以这不仅仅是一个 beta 问题。

Update - 7 Feb 12:

更新 - 12 年 2 月 7 日:

This seems like it may actually be a Ext.ux.grid.FilterFeatureproblem not an infinite scrolling problem. If I remove the FilterFeature config entirely infinite scrolling works great and does pass the sorting params to my backend when I sort by a column. I will start looking into the FilterFeature end of things.

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

采纳答案by vanderwyst

SUCCESS!I have infinite scrolling working with a remote filter and remote sort (this is in 4.1 beta 2, but because I was getting the same errors in 4.02a and 4.0.7 I imagine that it would resolve those too). Basically, I just had to add a few overrides in my code.

成功!我使用远程过滤器和远程排序进行无限滚动(这是在 4.1 beta 2 中,但因为我在 4.02a 和 4.0.7 中遇到相同的错误,我想它也会解决这些错误)。基本上,我只需要在我的代码中添加一些覆盖。

I haven't done testing in other browsers but I have it going in FF. Here are the overrides that I am using:

我还没有在其他浏览器中进行过测试,但我已经在 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();
    }
});

My store is configured like so:

我的商店配置如下:

// 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 grid is:

网格是:

// 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...],
});

Also the initial load must be done like this (not just store.load()):

初始加载也必须像这样完成(不仅仅是 store.load()):

store.prefetch({
    start: 0,
    limit: 200,
    callback: function() {
        store.guaranteeRange(0, 99);
    }
});    

回答by only1kairi

Your answer provided the right direction, I modified your code from

你的回答提供了正确的方向,我修改了你的代码

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

to

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

This fixed an issue of your previous filter returning empty results. After I inserted this change it was working correctly.

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