ExtJS Infinite Scroll Grid с удаленными фильтрами и сортировкой - PullRequest
17 голосов
/ 06 февраля 2012

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

Это нигде не сказано в документах (см. Раздел «Бесконечная прокрутка»), но вам нужно настроить свой магазин на настройку buffered: true. И вы не можете загрузить с store.load(), это нужно сделать так:

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

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

Однако, если я прокручиваю быстро или пытаюсь перезагрузить бесконечную сетку прокрутки с активным фильтром или во время сортировки все разрывается. Ошибка options is undefined.

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

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

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

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

В результате в обработчике 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);

},

Я могу вырезать вызов этого 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.

Ответы [ 2 ]

14 голосов
/ 08 февраля 2012

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

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

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

до

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

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

...