An annoying problem with paging grids is that they don't remember their selections across paging. This plugin fixes that by preserving selections across paging events and store reloads. It also provides methods to fetch and clear the entire selection (across all pages).
Licensed under http://www.gnu.org/licenses/lgpl-3.0.txt
Ext.ux.grid.RowSelectionPaging.js:
Code:
/**
* Ext.ux.grid.RowSelectionPaging plugin for Ext.grid.GridPanel
* A grid plugin that preserves row selections across paging / filtering of the store.
*
* @author Joeri Sebrechts
* @date October 21st, 2009
*
* @class Ext.ux.grid.RowSelectionPaging
* @extends Ext.util.Observable
*/
Ext.ns('Ext.ux.grid');
Ext.ux.grid.RowSelectionPaging = function(config) {
Ext.apply(this, config);
};
Ext.extend(Ext.ux.grid.RowSelectionPaging, Ext.util.Observable, {
init: function(grid) {
this.grid = grid;
this.selections = []; // array of selected records
this.selected = {}; // hash mapping record id to selected state
grid.on('render', function() {
// attach an interceptor for the selModel's onRefresh handler
this.grid.view.un('refresh', this.grid.selModel.onRefresh, this.grid.selModel);
this.grid.view.on('refresh', this.onViewRefresh, this );
// add a handler to detect when the user changes the selection
this.grid.selModel.on('rowselect', this.onRowSelect, this );
this.grid.selModel.on('rowdeselect', this.onRowDeselect, this);
// patch selModel to detect selection cleared events
var scope = this;
this.selModelClearSelections = this.grid.selModel.clearSelections;
this.grid.selModel.clearSelections = function(fast) {
scope.selModelClearSelections.call(this, fast);
scope.onSelectionClear();
};
// and replace the default behavior of the "check all"
if (!this.originalSelectAll && (this.grid.selModel.id == 'checker')) {
this.grid.selModel.onHdMouseDown = function(e, t) {
if(t.className == 'x-grid3-hd-checker'){
e.stopEvent();
var hd = Ext.fly(t.parentNode);
var isChecked = hd.hasClass('x-grid3-hd-checker-on');
if(isChecked){
hd.removeClass('x-grid3-hd-checker-on');
scope.clearSelections();
}else{
hd.addClass('x-grid3-hd-checker-on');
scope.selectAll();
}
}
}
}
}, this);
}, // end init
// private
onViewRefresh: function() {
this.ignoreSelectionChanges = true;
// explicitly refresh the selection model
this.grid.selModel.onRefresh();
// selection changed from view updates, restore full selection
var ds = this.grid.getStore();
var newSel = [];
for (var i = ds.getCount() - 1; i >= 0; i--) {
if (this.selected[ds.getAt(i).id]) {
newSel.push(i);
}
}
this.grid.selModel.selectRows(newSel, false);
this.ignoreSelectionChanges = false;
}, // end onViewRefresh
// private
onSelectionClear: function() {
if (! this.ignoreSelectionChanges) {
// selection cleared by user
// also called internally when the selection replaces the old selection
this.selections = [];
this.selected = {};
}
}, // end onSelectionClear
// private
onRowSelect: function(sm, i, rec) {
if (! this.ignoreSelectionChanges) {
if (!this.selected[rec.id])
{
this.selections.push(rec);
this.selected[rec.id] = true;
}
}
}, // end onRowSelect
// private
onRowDeselect: function(sm, i, rec) {
if (!this.ignoreSelectionChanges) {
if (this.selected[rec.id]) {
for (var i = this.selections.length - 1; i >= 0; i--) {
if (this.selections[i].id == rec.id) {
this.selections.splice(i, 1);
this.selected[rec.id] = false;
break;
}
}
}
}
}, // end onRowDeselect
/**
* Clears selections across all pages
*/
clearSelections: function() {
this.selections = [];
this.selected = {};
this.onViewRefresh();
}, // end clearSelections
/**
* Returns the selected records for all pages
* @return {Array} Array of selected records
*/
getSelections: function() {
return [].concat(this.selections);
}, // end getSelections
/**
* Selects all the rows in the grid, including those on other pages
* Be very careful using this on very large datasets
*/
selectAll: function() {
var ds = this.grid.getStore();
ds.suspendEvents();
ds.load({
params: {start: 0, limit: ds.getTotalCount() },
callback: function() {
this.selections = ds.data.items.slice(0);
this.selected = {};
for (var i = this.selections.length - 1; i >= 0; i--) {
this.selected[this.selections[i].id] = true;
};
ds.resumeEvents();
this.onViewRefresh();
},
scope: this
});
}
});
To use, just load it as a plugin:
Code:
var pagingSelection = new Ext.ux.grid.RowSelectionPaging();
...
plugins: [pagingSelection],
...
A demo can be found at http://sebrechts.net/demo/rowselectionpaging/
Update (2009-10-21):
I've added support for a true select all operation (via the checkbox selection model). To get back to original "select all" behavior, create the plugin with "new Ext.ux.grid.RowSelectionPaging({originalSelectAll: true})"
Update (2009-10-22):
Btw, yesterday's update was tested on 2.2 and 3.0, so it should be compatible with both releases.