4
votes

I've posted this over on the Sencha forums, wanted to also post it here just in case:

I have a GridPanel that utilizes a PagingToolbar and a CheckboxSelectionModel. I want to keep track of selections across pages. I'm nearly there, but I'm running into issues with the PagingToolbar controls (such as next page) firing a 'selectionchange' event on the my selection model.

Here's a simplified sample of my code:

Code:

var sm = Ext.create('Ext.selection.CheckboxModel', {
    listeners:{
        selectionchange: function(selectionModel, selectedRecords, options){
            console.log("Selection Change!!");
            // CODE HERE TO KEEP TRACK OF SELECTIONS/DESELECTIONS
        }
    }
});

var grid = Ext.create('Ext.grid.Panel', {
    autoScroll:true,
    store: store,
    defaults: {
        sortable:true
    },
    selModel: sm,
    dockedItems: [{
        xtype: 'pagingtoolbar',
        store: store,
        dock: 'bottom',
        displayInfo: true
    }],
    listeners: {'beforerender' : {fn:function(){
        store.load({params:params});

    }}}
});
store.on('load', function() {
    console.log('loading');
    console.log(params);
    console.log('selecting...');
    var records = this.getNewRecords();
    var recordsToSelect = getRecordsToSelect(records);
    sm.select(recordsToSelect, true, true);
});

I assumed that I could select the records on the load event and not trigger any events.

What's happening here is that the selectionchange event is being triggered on changing the page of data and I don't want that to occur. Ideally, only user clicking would be tracked as 'selectionchange' events, not any other component's events bubbling up and triggering the event on my selection model. Looking at the source code, the only event I could see that fires on the PagingToolbar is 'change'. I was trying to follow how that is handled by the GridPanel, TablePanel, Gridview, etc, but I'm just not seeing the path of the event. Even then, I'm not sure how to suppress events from the PagingToolbar to the SelectionModel.

Thanks in advance, Tom

3

3 Answers

6
votes

I've managed to handle that. The key is to detect where page changes. Easiest solution is to set buffer for selection listener and check for Store.loading property. Here is my implementation of selection model:

var selModel = Ext.create('Ext.selection.CheckboxModel', {
    multipageSelection: {},
    listeners:{
        selectionchange: function(selectionModel, selectedRecords, options){
            // do not change selection on page change
            if (selectedRecords.length == 0 && this.store.loading == true && this.store.currentPage != this.page) {
                return;
            }

            // remove selection on refresh
            if (this.store.loading == true) {
                this.multipageSelection = {};
                return;
            }

            // remove old selection from this page
            this.store.data.each(function(i) {
                delete this.multipageSelection[i.id];
            }, this);

            // select records
            Ext.each(selectedRecords, function(i) {
                this.multipageSelection[i.id] = true;
            }, this);
        },
        buffer: 5
    },
    restoreSelection: function() {
        this.store.data.each(function(i) {
            if (this.multipageSelection[i.id] == true) {
                this.select(i, true, true);
            }
        }, this);
        this.page = this.store.currentPage;
    }

And additional binding to store is required:

store.on('load', grid.getSelectionModel().restoreSelection, grid.getSelectionModel());

Working sample: http://jsfiddle.net/pqVmb/

0
votes

Lolo's solution is great but it seems that it doesn't work anymore with ExtJS 4.2.1.

Instead of 'selectionchange' use this:

deselect: function( selectionModel, record, index, eOpts ) {
    delete this.multipageSelection[i.id];
},

select: function( selectionModel, record, index, eOpts ) {
     this.multipageSelection[i.id] = true;
},
0
votes

This is a solution for ExtJs5, utilizing MVVC create a local store named 'selectedObjects' in the View Model with the same model as the paged grid.

Add select and deselect listeners on the checkboxmodel. In these functions add or remove the selected or deselected record from this local store.

onCheckboxModelSelect: function(rowmodel, record, index, eOpts) {
    // Add selected record to the view model store
    this.getViewModel().getStore('selectedObjects').add(record);
},

onCheckboxModelDeselect: function(rowmodel, record, index, eOpts) {
    // Remove selected record from the view model store
    this.getViewModel().getStore('selectedObjects').remove(record);
},

On the pagingtoolbar, add a change listener to reselect previously seleted records when appear in the page.

onPagingtoolbarChange: function(pagingtoolbar, pageData, eOpts) {
    // Select any records on the page that have been previously selected
    var checkboxSelectionModel = this.lookupReference('grid').getSelectionModel(),
        selectedObjects = this.getViewModel().getStore('selectedObjects').getRange();

    // true, true params. keepselections if any and suppresses select event. Don't want infinite loop listeners.
    checkboxSelectionModel.select(selectedObjects, true, true);
},

After whatever action is complete where these selections are no longer needed. Call deselectAll on the checkboxmodel and removeAll from the local store if it will not be a destroyed view. (Windows being closed, they default set to call destroy and will take care of local store data cleanup, if that is your case)