Подтвердить что ты не робот

ExtJS Infinite Scroll Grid с дистанционными фильтрами и сортировкой

В 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.

Я потратил пару часов на выполнение некоторых трассировок кода и googling, и кроме того, что никто не реализовал бесконечную сетку прокрутки с удаленными фильтрами и удаленной прокруткой, я нашел следующее:

Фильтрация разрушается из-за этого метода в Ext.data.Store, который вызывается бесконечным скроллером, когда ему требуется больше данных с сервера:

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

По какой-то причине этот метод запускает событие beforeload без параметра Ext.data.Operation, который должен быть частью его, как указано здесь.

В результате в обработчике onbeforeload в Ext.ux.grid.FiltersFeature возникает ошибка, поскольку, конечно, "параметры" - это undefined:

/**
 * @private
 * Handler for store 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);

},

Я могу вырезать вызов этого метода mask из кода PagingScroller, и тогда функция прокрутки великолепна. Я могу прокручивать так быстро, как мне нравится, и он правильно загружает данные. Но, тогда фильтры и сортировка не будут применяться к запросам ajax.

Я не так много погрузился в сортировку, но я думаю, что это похоже на этот метод mask, потому что sort - это просто другой элемент, содержащийся в объекте operation, и он вызывает no который будет передан в запрос ajax.

Я думаю, что если бы я мог просто выяснить, как заставить метод mask запускать beforeload с параметром operation (например, как говорят документы, он должен) все будет хорошо. Проблема в том, что я не смог понять, как это сделать. Любые предложения?

Если кто-то просто скажет мне, что я ошибаюсь, и люди действительно сделали эту работу, я был бы вдохновлен, но фрагмент любых переопределений, которые вы использовали для решения этой проблемы, или ссылка была бы очень оценена.

Я также попытался понизить до 4.0.7 и 4.0.2a, и получаю те же результаты, поэтому это не просто бета-версия.

Обновление - 7 февраля 12:

Кажется, что это может быть проблема Ext.ux.grid.FilterFeature, а не бесконечная проблема прокрутки. Если я удалю конфигурацию FilterFeature, то бесконечная прокрутка отлично работает и передаёт параметры сортировки на мой бэкэнд, когда я сортирую по столбцу. Я начну смотреть на конец FilterFeature.

4b9b3361

Ответ 1

УСПЕХ! У меня бесконечная прокрутка, работающая с удаленным фильтром и удаленным сортированием (это в бета-версии 4.1, но поскольку я получал те же ошибки в 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);
    }
});    

Ответ 2

Ваш ответ был в правильном направлении, я изменил код из

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

к

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

Это фиксировало проблему вашего предыдущего фильтра, возвращающего пустые результаты. После того, как я вставил это изменение, он работал правильно.