带有远程过滤器和排序的 ExtJS 无限滚动网格 [英] ExtJS Infinite Scroll Grid with remote Filters and Sort

查看:23
本文介绍了带有远程过滤器和排序的 ExtJS 无限滚动网格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 ExtJS 4.1 beta 2 中,我设法实现了一个带有远程存储的无限滚动网格.我基本上采用了现有的(完全可操作的)分页网格(带有远程存储、过滤和排序),然后放入适当的配置以进行无限滚动:

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:

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

文档(参见无限滚动部分),但您需要将您的商店设置为具有 buffered: true 配置.而且你不能用 store.load() 加载它需要这样做:

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

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.

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

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:

由于 Ext.data.Store 中的这个方法导致过滤失败,当无限滚动器需要来自服务器的更多数据时,它会调用该方法:

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

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

出于某种原因,此方法触发 beforeload 事件 没有 Ext.data.Operation 参数,它应该是它的一部分如此处所指定.

For some reason, this method fires the beforeload event without the Ext.data.Operation parameter which is supposed to be part of it as specified here.

因此,Ext.ux.grid.FiltersFeature 中的 onbeforeload 处理程序发生错误,因为选项"当然未定义:

As a result, an error occurs in the onbeforeload handler in Ext.ux.grid.FiltersFeature because of course "options" is undefined:

/**
 * @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请求.

I can cut out the call to this mask method 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. But then filters and sort does not get applied to the ajax requests.

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

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

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

I'm thinking that if I could just figure out how to force the mask method to fire beforeload with the operation parameter (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?

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

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.

我也试过降级到 4.0.7 和 4.0.2a 并且得到相同的结果,所以这不仅仅是测试版问题.

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.

更新 - 12 年 2 月 7 日:

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

This seems like it may actually be a Ext.ux.grid.FilterFeature problem 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.

推荐答案

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

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.

我还没有在其他浏览器中进行过测试,但我已经在 FF 中进行了测试.以下是我正在使用的覆盖:

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

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 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()):

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

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

这篇关于带有远程过滤器和排序的 ExtJS 无限滚动网格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆