PDA

View Full Version : "Smart" CheckBoxSelectionModel



NoahK17
4 Jun 2008, 1:32 PM
This modification is based on the standard grid CheckboxSelectionModel but with a twist: it will check/select specific rows when a grid loads based on a dataIndex YOU supply!

Features:
- Selects and checks grid rows based off JSON/XML response from server upon initial load
- Remembers state of grid as you reorder columns
- Checkbox clicking and Row selecting can work together, separate, or even as a combination of the two
- Includes all functionality of both the RowSelectionModel and the CheckboxSelectionModel

Compatibility:
- This extension has been tested and works properly with ExtJS version 2.1 through 3.1.2
- This extension works properly with Saki's RowAction, CellAction, and HttpProvider extensions.

Usage:


var sm = new Ext.grid.SmartCheckboxSelectionModel({
dataIndex:'checked',
email: true, // separates checkbox clicking from row selecting
});

Store Data:
All you have to do is set 'checked' to be 'true' or 'false' in your Array or JSON/XML string. For example:


{"totalCount":1,"data":[{"checked":"true","id":"1","location":"Atlanta","product":"Retail","car":"Luxury"},{"checked":"false","id":"2","location":"Atlanta","product":"Retail","car":"SUV"}]}


We pass in the supplied variable and voila, the grid is rendered with specific rows pre-checked AND pre-selected. Just add the selectionModel to your reader and gridPanel and you're done.

Options:
- excel: if set to true, your grid selection will work like Microsoft Excel. Clicking a row selects that row. Clicking a second row, unselects the first row and selects the new row instead. Holding down CTRL or Shift selects multiple rows at once. If this option is set to false (the default), then CTRL is assumed to be held down as you click different rows.
- email: if set to true, the checking of a checkbox and the selecting of a row will be separated out. When you click a checkbox, only the checkbox will be checked; the row itself will not become selected. This allows you to apply different actions on rows based on whether the row is checked, selected, or a combination of the two. The default is false, meaning as you click a checkbox it will also select the row, and vice-versa.
- alwaysSelectOnCheck: if set to true, clicking a checkbox will always select the row... but selecting a row will NOT check the checkbox. The default is false, and this option works in conjunction with the email option.
- useStateManager: if set to true, the built-in Cookie StateManager will be used, unless you are using an alternative StateManager such as Saki's Http StateManager. if set to false, the Cookie StateManager will not be used. If you are having compatibility issues with other StateManagers or just don't need that functionality for your project, set this config option to false.

More Details:
- All the base functionality of the standard RowSelectionModel and CheckboxSelectionModel are present, including using the UP and DOWN arrow keys to navigate (select/check) up and down the grid, using SHIFT to select multiple rows at once, clicking the checkbox header to check/select and uncheck/de-select all the rows, and simple clicking around the grid to select anything you desire.

Latest Updates:
v.1.8 <March 23, 2011>: new features, bug fixes, compatibility fixes
- new events, "checked" and "beforerowdeselect", both user requested
- new config option, "useStateManager", set to true to use the Cookie StateManager by default, or false to use your own StateManager
- compatibility fix, the default Cookie StateManager no longer conflicts with Saki's Http StateManager
- bug fix, the header ID is now uniquely generated as to avoid conflicts with multiple grids rendered on the same page
- tested with ExtJS v.3.2.1; let me know if there are any issues!



/**
* @class Ext.grid.SmartCheckboxSelectionModel
* @extends Ext.grid.RowSelectionModel
*
* A custom selection model that renders a column of checkboxes that can be toggled to select or deselect rows.
* By passing in a dataIndex and a store, it can pre-check (and select) rows after it renders.
* Included are all the standard navigation options of a RowSelectionModel, including Up/Down arrow keyMaps and Ctrl/Shift selections.
*
* @param (object) config The configuration options, as highlighted below
* @param (string) dataIndex The field that contains the boolean true/false value for checked/selected rows
*
* @copyright June 4, 2008 <last updated: March 23, 2011>
* @author NoahK17
* @version 1.8
*/
Ext.grid.SmartCheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {
/**
* @width (int) The default width in pixels of the checkbox column (defaults to 20).
*/
width: 20,
/**
* @sortable (bool) Set to true if you want the checkbox column to be sortable.
*/
sortable: false,
/**
* @email (bool) Will mimic email client functionality by separating out the selection of rows
* with the checking of rows, similar to how Yahoo! or Gmail works. One could then
* apply different actions on checked rows vs. selected rows.
* Defaults to false.
*/
email: false,
/**
* @excel (bool) Mimics excel functionality when clicking on rows or checkboxes. If set to true,
* all other rows will be deselected and unchecked except the row you most recently
* clicked. If set to false, all previous selections will remain selected and/or checked
* as you click around the grid (as if you were holding down CTRL and clicking).
* Defaults to true.
*/
excel: true,

/**
* @alwaysSelectOnCheck
* (bool) If set to true, clicking a checkbox will always select the row, working in conjunction
* with the email option.
* Defaults to false.
*
*/
alwaysSelectOnCheck: false,

/**
* @userStateProvider
* (bool) If set to true, the selection model will attempt to use the CookieState Provider by
* default, unless you are already using a different provider, such as Saki's HttpProvider,
* in which case the already existing provider will be used. If set to false, no provider
* will be used, which may allow for better compatibility.
* Defaults to true.
*
*/
useStateProvider: true,

// private
menuDisabled:true,
fixed:true,
id: 'checker',
dataIndex: '', // Define the dataIndex when you construct the selectionModel, not here

constructor: function()
{
// Define the header using a unique Id (e.g., ext-gen12)
this.headerId = Ext.id();
this.header = '<div id="'+ this.headerId +'" class="x-grid3-hd-checker"> </div>';

// Add some events
this.addEvents(
/**
* @event check
* Fires when the checkbox is checked or unchecked.
* @param {SelectionModel} this
* @param {Number} rowIndex The checked row index
* @param {Ext.data.Record} r The checked record
* @param {Bool} checked The new checked value
*/
"check", // courtesy of Sencha forum user renku

/**
* @event beforerowdeselect
* Fires just before a row is de-selected.
* @param {SelectionModel} this
* @param {Number} rowIndex The row's row index
* @param {Ext.data.Record} r The row's record
*/
"beforerowdeselect" // user requested
);

// Call the parent
Ext.grid.SmartCheckboxSelectionModel.superclass.constructor.apply(this,arguments);
},

// private
initEvents : function(){
// Call the parent
Ext.grid.SmartCheckboxSelectionModel.superclass.initEvents.call(this);

// Assign the handlers for the mousedown events
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
Ext.fly(view.innerHd).on('mousedown', this.onHdMouseDown, this);
}, this);
// Disable the rowNav created in our parent object, otherwise pressing DOWN will go down two rows!
this.rowNav.disable();
// Create our new rowNav that controls checkboxes as well
this.rowNav2 = new Ext.KeyNav(this.grid.getGridEl(), {
"up" : function(e){
if(!e.shiftKey){
if (!this.email) {
this.selectPreviousChecked(e.shiftKey);
} else {
this.selectPrevious(e.shiftKey);
}
} else if(this.last !== false && this.lastActive !== false) {
var last = this.last;
if (!this.email) {
this.selectRangeChecked(this.last, this.lastActive-1);
} else {
this.selectRange(this.last, this.lastActive-1);
}
this.grid.getView().focusRow(this.lastActive);
if (last !== false) {
this.last = last;
}
} else {
this.selectFirstRow();
if (!this.email) { this.toggleChecked(0, true); }
}
},
"down" : function(e){
if(!e.shiftKey){
if (!this.email) {
this.selectNextChecked(e.shiftKey);
} else {
this.selectNext(e.shiftKey);
}
} else if (this.last !== false && this.lastActive !== false) {
var last = this.last;
if (!this.email) {
this.selectRangeChecked(this.last, this.lastActive+1);
} else {
this.selectRange(this.last, this.lastActive+1);
}
this.grid.getView().focusRow(this.lastActive,true);
if (last !== false) {
this.last = last;
}
} else {
this.selectFirstRow();
if(!this.email){ this.toggleChecked(0, true); }
}
},
scope: this
});
// Listen for the movement of the columns
this.grid.on('columnmove', function(p){
var t = Ext.get(this.headerId);
if (t != null) {
if(t.dom.className != 'x-grid3-hd-checker'){
Ext.fly(t.dom.parentNode).removeClass('x-grid3-hd-checker');
}
}
});
// If we sent a store to the selModel, auto-select rows based on dataIndex
if (this.grid.store){
this.grid.store.on('load', function(p){
// This block of code checks the status of the checkbox header,
// and if checked, will check all other checkboxes (but not on the initial load)
var t = Ext.get(this.headerId);
if (t != null) {
if(t.dom.className == 'x-grid3-hd-checker'){
if (this.useStateProvider) {
if (Ext.state.Manager.loaded) {
var hd = Ext.fly(t.dom.parentNode);
var isChecked = hd.hasClass('x-grid3-hd-checker-on');
if (isChecked) {
hd.addClass('x-grid3-hd-checker-on');
if(!this.email){ this.selectAll(); }
this.selectAllChecked(true);
}
}
} else {
var hd = Ext.fly(t.dom.parentNode);
var isChecked = hd.hasClass('x-grid3-hd-checker-on');
if (isChecked) {
hd.addClass('x-grid3-hd-checker-on');
if(!this.email){ this.selectAll(); }
this.selectAllChecked(true);
}
}
} else {
Ext.fly(t.dom.parentNode).removeClass('x-grid3-hd-checker');
}
}

// This block of code will pre-select checkboxes based on the dataIndex supplied,
// but only on the initial load.
var dataIndex = this.grid.getSelectionModel().dataIndex; // the dataIndex for the selectionModel
var count = this.grid.store.getCount();
for (var i = 0, len = count; i < len; i++) {
var dataIndexValue = this.parseBoolean(p.data.items[i].data[dataIndex]); // the value of the dataIndex for each row
var isSelected = this.isSelected(i);
if (dataIndexValue == true || isSelected) {
if (this.useStateProvider) {
if (!Ext.state.Manager.loaded) {
// This code will only run the first time a grid is loaded
// Make sure that any "checked" rows are also selected
if (!this.email || this.alwaysSelectOnCheck) { this.grid.getSelectionModel().selectRow(i, true); }
}
} else {
if (!this.email || this.alwaysSelectOnCheck) { this.grid.getSelectionModel().selectRow(i, true); }
}
} else if(isSelected) {
// Let the state.Manager check the correct rows now
if(!this.email){ this.toggleChecked(i, true); }
} else {
// Uncheck everything else
if(!this.email){ this.toggleChecked(i, false); }
}
}
}, this);
}
},

/**
* private custom function written by Sencha forum user Greffin
*
* this ensures that the true/false value of the dataIndex
* is actually a boolean value and not a string
*
* @param (mixed) value the value you want to check
*
* @access private
*/

parseBoolean : function(value){
if (Ext.isDefined(value) && Ext.isString(value)) {
return (value.toLowerCase() == 'true' ? true:false);
}
return value;
},

/**
* private function that controls the checkboxes
*
* @param (int) rowIndex the row you want to toggle
* @param (bool) c optional flag set to either true (to check) or false (to uncheck)
* if no second param, the checkbox will toggle itself
*
* @access private
*/
toggleChecked : function(rowIndex, c){
if (this.locked) { return; }
var record = this.grid.store.getAt(rowIndex);
// Determine if we are checking, unchecking, or toggling
var checked = (typeof c === "boolean") ? c : !record.data[this.dataIndex];
// Set the record
record.set(this.dataIndex, checked);
// Fire the "check" event
this.fireEvent("check", this, rowIndex, record, checked);
},

/**
* private functions that toggles all checkboxes on or off depending on param
*
* @param (bool) c true to check all checkboxes, false to uncheck all checkboxes
* @param (int) e (optional) if an exception is given, all rows will be checked/unchecked except this row
*/
selectAllChecked : function(c, e){
if (this.locked) { return; }
var count = this.grid.store.getCount();
for (var i = 0, len = count; i < len; i++) {
if(c){
if(i !== e){
this.toggleChecked(i, true);
}
} else {
if(i !== e){
this.toggleChecked(i, false);
}
}
}
},

/**
* private function that clears all checkboxes
* specifically used to deal with shift+arrow keys,
* but can also be called with fast param to quickly uncheck everything
*
* @param (bool) fast true to quickly deselect everything with no exceptions
*
* @access private
*/
clearChecked : function(fast){
if (this.locked) { return; }
if (fast !== true) {
var count = this.grid.store.getCount();
for(var i = 0, len = count; i < len; i++){
var isSelected = this.isSelected(i);
if(!isSelected){
this.toggleChecked(i, false);
}
}
} else {
// Quick and dirty method to uncheck everything
this.selectAllChecked(false);
}
this.last = false;
},

/**
* private function used in conjuction with the shift key for checking multiple rows at once
*
* @access private
*/
selectRangeChecked : function(startRow, endRow, keepExisting){
if (this.locked) { return; }
if (!keepExisting) {
if(!this.email || this.alwaysSelectOnCheck){ this.clearSelections(); }
this.clearChecked();
}
if (startRow <= endRow) {
for(var i = startRow; i <= endRow; i++){
if(this.grid.store.getAt(i)){
this.toggleChecked(i, true);
if(!this.email || this.alwaysSelectOnCheck){ this.selectRow(i, true); }
}
}
} else {
for (var i = startRow; i >= endRow; i--) {
if (this.grid.store.getAt(i)) {
this.toggleChecked(i, true);
if(!this.email || this.alwaysSelectOnCheck){ this.selectRow(i, true); }
}
}
}
},

/**
* private function that is used with the UP arrow keyMap
*
* @access private
*/
selectPreviousChecked : function(keepExisting){
if(this.hasPrevious()){
// Select the next row
this.selectRow(this.last-1, keepExisting);
// Set the focus
this.grid.getView().focusRow(this.last);
if(!this.email){
// Check the current (selected) row
this.toggleChecked(this.last, true);
// Uncheck all other rows
this.selectAllChecked(false, this.last);
}
return true;
}
return false;
},

/**
* private function that is used with the DOWN arrow keyMap
*
* @access private
*/
selectNextChecked : function(keepExisting){
if(this.hasNext()){
// Select the next row
if(!this.email){ this.selectRow(this.last+1, keepExisting); }
// Set the focus
this.grid.getView().focusRow(this.last);
if(!this.email){
// Check the current (selected) row
this.toggleChecked(this.last, true);
// Uncheck all other rows
this.selectAllChecked(false, this.last);
}
return true;
}
return false;
},

/**
* private function that executes when you click on any row
* will keep other row selections active as you click around
*
* @access private
*/
handleMouseDown : function(g, rowIndex, e){
var t = e.getTarget('.ux-row-action-item');
if (!t) {
if(e.button !== 0 || this.isLocked()){
return;
};
var view = this.grid.getView();
var record = this.grid.store.getAt(rowIndex);
if (e.shiftKey && this.last !== false) {
var last = this.last;
this.selectRange(last, rowIndex, e.ctrlKey);
if(!this.email){ this.selectRangeChecked(last, rowIndex, e.ctrlKey); }
this.last = last; // reset the last
view.focusRow(rowIndex);
} else {
var isChecked = this.parseBoolean(record.data[this.dataIndex]);
var isSelected = this.isSelected(rowIndex);

if (isSelected) {
this.fireEvent("beforerowdeselect", this, rowIndex, record);
this.deselectRow(rowIndex);
if(!this.email){ this.toggleChecked(rowIndex, false); }
} else {
if (!this.excel) {
this.selectRow(rowIndex, true);
if(!this.email){
this.toggleChecked(rowIndex, true);
}
} else {
this.selectRow(rowIndex, e.ctrlKey);
if(!this.email){
this.selectRangeChecked(rowIndex, rowIndex, e.ctrlKey);
}
}
view.focusRow(rowIndex);
}
}
}
},

/**
* private function restricted to execute when you click a checkbox itself
*
* @access private
*/
onMouseDown : function(e, t){
if(t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
e.stopEvent();
// Define variables
var view = this.grid.getView();
var rowIndex = view.findRowIndex(t);
var record = this.grid.store.getAt(rowIndex);
var isSelected = this.isSelected(rowIndex);
var isChecked = this.parseBoolean(record.data[this.dataIndex]);
// Logic to select/de-select rows and the checkboxes
if (!this.email || this.alwaysSelectOnCheck) {
if (isSelected){
if (!isChecked && this.alwaysSelectOnCheck) {
this.toggleChecked(rowIndex, true);
} else {
this.fireEvent("beforerowdeselect", this, rowIndex, record);
this.deselectRow(rowIndex);
this.toggleChecked(rowIndex, false);
}
} else {
this.selectRow(rowIndex, true);
this.toggleChecked(rowIndex, true);
view.focusRow(rowIndex);
}
} else {
if (isChecked){
this.toggleChecked(rowIndex, false);
} else {
this.toggleChecked(rowIndex, true);
}
}
view.focusRow(rowIndex);
}
// Load the state manager if one does not already exist
if (this.useStateManager) {
if (typeof Ext.state.Manager.getProvider().path == 'undefined') {
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
}
Ext.state.Manager.loaded = true;
}
},


/**
* private function that executes when you click the checkbox header
*
* @access private
*/
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');
if(!this.email || this.alwaysSelectOnCheck){ this.clearSelections(); }
this.clearChecked(true); // the true param enables fast mode
} else {
hd.addClass('x-grid3-hd-checker-on');
if(!this.email || this.alwaysSelectOnCheck){ this.selectAll(); }
this.selectAllChecked(true);
}
}
// Load the state manager if one does not already exist
if (this.useStateManager) {
if (typeof Ext.state.Manager.getProvider().path == 'undefined') {
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
}
Ext.state.Manager.loaded = true;
}
},

/**
* private function that renders the proper checkbox based on your dataIndex variable
*
* @param (varchar) v the dataIndex passed into the selectionModel that contains whether a row is checked by default or not
*
* @access private
*/
renderer : function(v, p, record){
p.css += ' x-grid3-check-col-td';
v = this.parseBoolean(v); // make sure the v variable is a boolean value
return '<div class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'"> </div>';
}
});
/* eof */

Version History:
v1.0 <June 4, 2008>: initial release
v1.1 <June 5, 2008>: bug fixes and new features
- added state.Manager functionality to ensure checked/selected state is saved after initial load
- added more "smart" when handling shift+selecting up and down the grid
- removed need to include the gridID parameter
- more commenting added
v1.2 <June 6, 2008>: bug fix
- changed location of state.Manager to remember the state of the grid after any onClick
v1.3 <June 9, 2008>: new features
- the paging.Toolbar now remembers the state of the header checkbox, so records can be auto-selected as you page
- removed need to include the store in the selection model
v1.4 <June 23, 2008>: bug fixes and new features
- added two new config options, "email" and "excel", see documentation for more details
- fixed small bug if checkbox header was disabled
- more commenting added
v1.5 <June 24, 2008>: bug fixes and a new feature
- added new config option, "alwaysSelectOnCheck", see documentation for more details
- fixed bug using up and down arrow keys
- replaced a small piece of ASCII code that was translating into an * on the forums
v1.6 <June 26, 2008>: compatibility fix
- added code to make this selectionModel compatible with Saki's "RowActions" plugin
v.1.7 <July 1, 2008>: bug fix
- added support for non-checkbox/non-blank headers; see documentation for specific usage

NoahK17
5 Jun 2008, 7:50 AM
Attached is a screenshot which shows rows being pre-selected and pre-checked based off a JSON response string from a PHP script using a MySQL server.

mystix
5 Jun 2008, 7:55 AM
eh? where's the screenshot?

NoahK17
5 Jun 2008, 8:10 AM
Whoops, all fixed. It basically combines the functionality of a RowSelectionModel (up/down arrows, shift/ctrl selection), and a CheckboxSelectionModel (header check all/uncheck all) and the additional functionality of pre-checking/selecting rows based off the selectionModel dataIndex and saving the state as you re-order columns.

Woohoo!

Feel free to offer any suggestions! :)

NoahK17
9 Jun 2008, 8:33 AM
Upgraded to v1.3 with new features:
- If you click the header checkbox, this SmartCheckboxSelectionModel assumes that you want to select ALL records, and not just what appears on the grid. If you have 100 records, but only show 10 at a time, clicking the header checkbox will "select" all 100 records, so as you page, you will see every record checked. If you do not desire this functionality, the new block of code can easily be commented out.
- In addition, you no longer need to manually send in the store to the selectionModel, as the store is now derived from the grid itself.

Cheers!

galdaka
9 Jun 2008, 9:15 AM
Excellent work,

Please live example for test!!!

Thanks in advance,

sistasi
11 Jun 2008, 8:46 AM
it's a great plugin, however with this pllugin, everytime the row is selected the checked will automatically be true, then i cannot have a link within the grid value.
because everytime i click on the link, it will remove the check if it is checked.
any idea how to solve this?
thanks.

NoahK17
11 Jun 2008, 9:07 AM
Using a regular selectionModel, how did you solve this issue? I have not tried to deal with links in the template of a row before, but I can definitely look into it for you.

A quick fix might be to edit this function:


/**
* private function that executes when you click on any row
* will keep other row selections active as you click around
*/
handleMouseDown : function(g, rowIndex, e){
if(e.button !== 0 || this.isLocked()){
return;
};
var view = this.grid.getView();
var record = this.grid.store.getAt(rowIndex);
if(e.shiftKey && this.last !== false){
var last = this.last;
this.selectRange(last, rowIndex, e.ctrlKey);
this.selectRangeChecked(last, rowIndex, e.ctrlKey);
this.last = last; // reset the last
view.focusRow(rowIndex);
}else{
this.toggleChecked(rowIndex);
var isChecked = record.data[this.dataIndex];
var isSelected = this.isSelected(rowIndex);

if (isSelected){
this.deselectRow(rowIndex);
this.toggleChecked(rowIndex, false);
}else{
this.selectRow(rowIndex, true);
this.toggleChecked(rowIndex, true);
view.focusRow(rowIndex);
}
}
},

The lines in red make the checkbox become "checked" when you click a row. You could comment out those lines, or add some sort of check (if row = link, don't uncheck).

Let me know if that helps you out at all.

Cheers!

sistasi
12 Jun 2008, 5:59 PM
thanks commenting that part of code will do the same thing.

however when i uncomment all after else part, it will work.


/**
* private function that executes when you click on any row
* will keep other row selections active as you click around
*/
handleMouseDown : function(g, rowIndex, e){
if(e.button !== 0 || this.isLocked()){
return;
};
var view = this.grid.getView();
var record = this.grid.store.getAt(rowIndex);
if(e.shiftKey && this.last !== false){
var last = this.last;
this.selectRange(last, rowIndex, e.ctrlKey);
this.selectRangeChecked(last, rowIndex, e.ctrlKey);
this.last = last; // reset the last
view.focusRow(rowIndex);
}else{
/* this.toggleChecked(rowIndex);
var isChecked = record.data[this.dataIndex];
var isSelected = this.isSelected(rowIndex);

if (isSelected){
this.deselectRow(rowIndex);
this.toggleChecked(rowIndex, false);
}else{
this.selectRow(rowIndex, true);
this.toggleChecked(rowIndex, true);
view.focusRow(rowIndex);
}*/
}
},

:D Thanks.

NoahK17
12 Jun 2008, 7:44 PM
Also comment out this line:

this.toggleChecked(rowIndex);

See if that works for you :)

thephatness
17 Jun 2008, 12:56 AM
Hi Noah,

Thanks for the great work on this...

I'm having a problem with the 'checked' dataIndex. What's happening is that all checks are being rendered backwards so to get it working right I would have to pass in 'checked':'false' for checked and 'checked':'true' for unchecked. Maybe it's late and I'm not reading it right but I've defined the SM just like in your usage guideline, and added a few listener functions to handle select/deselect AJAX requests. I wasn't sure what you meant by "Just add the selectionModel to your reader..." but I'm using the SM in the column model and selection model param for the datagrid. I also notice that when paging through the datagrid, for a split second, all checkboxes get checked and unchecked. Other than that everything works fine. I'll look into this more tomorrow and step it through Firebug. Thanks!

NoahK17
17 Jun 2008, 6:43 AM
Hrm, interesting. Here's how I have it set up:



// Create the data store
var myDataStore = new Ext.data.JsonStore({
url: '/repository/libs/php/grid-data.php',
root: 'data',
totalProperty: 'totalCount',
id: 'id',
fields: [
{name: 'checked', type: 'bool'}
]
});

// Define the selection model (checkbox)
var sm = new Ext.grid.SmartCheckboxSelectionModel({
dataIndex:'checked'
});

var cm = new Ext.grid.ColumnModel([
sm
]);

var grid = new Ext.grid.GridPanel({
cm: cm,
sm: sm,
ds: myDataStore,
width: 100,
height: 100
});

// Code to render your grid
...

// Trigger the data store load
myDataStore.load({params:.........});


My JSON response would look simply like:


{"totalCount":2,"data":[{"checked":"false", "id":"1"}, {"checked":"true", "id":"2"}]}

thephatness
17 Jun 2008, 8:29 PM
Thanks, that example is helpful. It was my lazy definition of fields: ['checked', 'field1', 'field2',...etc] instead of specifying fields: [{name: 'checked', type: 'bool'},... that caused the problem.

iuri.andreazza
20 Jun 2008, 6:20 AM
Hello! I put 'header:false" to not show the check in header, when the store loaded the data, the load event has an error and could not select the lines in the grid.

Then I fixed your code, is just only one more IF.
:)

On the initEvents
Code:


if (this.grid.store){
this.grid.store.on('load', function(p){
var t = Ext.get('x-grid3-hd-checker');
if(t != null){
if(t.dom.className == 'x-grid3-hd-checker' && Ext.state.Manager.loaded){
var hd = Ext.fly(t.dom.parentNode);
var isChecked = hd.hasClass('x-grid3-hd-checker-on');
if(isChecked){
hd.addClass('x-grid3-hd-checker-on');
this.selectAll();
this.selectAllChecked(true);
}
}
}
//... code

NoahK17
23 Jun 2008, 10:26 AM
Updated to v1.4:
- new config options, "email" and "excel"

email: Setting email to true or false in the selection model constructor changes the default behavior of the checkboxes. If set to true, clicking a checkbox will NOT change the row selection, it will ONLY check or uncheck the checkbox itself. This mimics the way various "email clients" behave, like Yahoo! or Gmail! Having email set to true allows you to apply different actions on your grid rows based on whether they are checked OR selected. If set to false, clicking a checkbox will also select the row and vice-versa. This setting defaults to false.

excel: Setting excel to true or false changes the way row selection works. If excel is set to true, clicking on a row will deselect all other rows, except for the row you just clicked. If set to false, all previous row selections will remain selected as you click around (just as if you were holding down CTRL and clicking a new row). This setting defaults to false.

Cheers!

Max Ishchenko
24 Jun 2008, 4:58 AM
I'm using the SmartCheckboxSelectionModel in a grid which is hidden by default. It's located in a tab with lazy loading.
I use loadData for loading the store, and checkboxes are checked correctly, but the rows with checked checkboxes are not selected. When clicking on the raw that was checked (but not selected) it gets checked, and the checkbox remains checked. Next clicks check/uncheck the checkbox and select/deselect the row.
I'd like to have not only checkboxes checked, but rows selected on load.
It seems that 'load' event listener does this, but it is not being invoked at all when using loadData (or supplying 'data' config option in store config).

Max Ishchenko
24 Jun 2008, 5:33 AM
My problem is solved now.
If you use inline data for your store (i.e. 'data' config parameter) the selectionmodel won't be attached to 'load' event listeners yet. Thus, no rows will be actually selected.
The solution is like


mygrid.on('render', function () {
this.getStore().loadData(mydata)
})

NoahK17
24 Jun 2008, 7:16 AM
Score! Glad you figured it out :)

Mthor
24 Jun 2008, 8:32 AM
is there a way to have email set to true and when check box is checked the row gets selected.

I need to only be able to check the check box, but the row gets selected when the check box is selected.

and if clicked anywhere on the row nothing happens

thanks

NoahK17
24 Jun 2008, 8:46 AM
Sure, you'd just have to add a new config option... then do an if/else statement in the store.load function.

Example:



var sm = new Ext.grid.SmartCheckboxSelectionModel({
dataIndex:'checked',
email:true,
mthor:true
});


Around line 132


if((dataIndexValue == true || isSelected) && !Ext.state.Manager.loaded){
// This code will only run the first time a grid is loaded
// Make sure that any "checked" rows are also selected
if(!this.email || this.mthor){ this.grid.getSelectionModel().selectRow(i, true); }
}


Then go through the rest of the code and look for !this.email -- and anywhere you want that functionality to be over-ridden (e.g. clicking of checkboxes), just add the || this.mthor piece of code. The || stands for ELSE.

Cheers!

NoahK17
24 Jun 2008, 9:21 AM
mthor: Your wish has been granted. I just updated the Smart CheckboxSelectionModel to version 1.5 with the feature you described above. Please download the latest version and use the new config option "alwaysSelectOnCheck". Cheers!

Updated to v1.5:
- bug fixes and new config option, "alwaysSelectOnCheck"

alwaysSelectOnCheck: Setting this option to true will always select a row as you click on a checkbox. It works in conjunction with the "email" option to further enchance your grid's functionality. The default for this option is false.

Mthor
24 Jun 2008, 9:40 AM
the new version works like a charm. thanks again for your quick fixes and reply.

Mthor
24 Jun 2008, 10:21 AM
is there an event for the checkbox only.

what is going on is, when I select the row the check box does not select (exactly what I needed) and now with the new version when a check box is selected the row is selected (works exactly how I wanted, thanks) but the new issue is if clicked on a row and I hit save changes on my grid, the row is being read and deleted without the check box being selected. I hope I explained that well enough.

NoahK17
24 Jun 2008, 10:25 AM
Mthor: You'll need to change the functionality of your delete function. You would need to check to see if a row is "checked" and not just "selected" -- if you look through the selection model, you can see code that shows how to see if a row isChecked vs. isSelected.

I would write a new function perhaps called "getChecked" that loops through the grid and returns a list of rows that are checked.

Good luck Mthor.

NoahK17
26 Jun 2008, 7:59 AM
Updated to v1.6 to include a small compatibility fix to work with Saki's RowActions plugin. Cheers!

iuri.andreazza
26 Jun 2008, 11:17 AM
bug found. When event beforerowselect returns false the row is not selected, but the check marked as checked.

For create a work around this, I've overwrite the selectRow method to return boolean when the row has been selected:



selectRow : function(index, keepExisting, preventViewNotify){
if(this.fireEvent("beforerowselect", this, index, keepExisting, preventViewNotify) !== false){
Ext.grid.SmartCheckboxSelectionModel.superclass.selectRow.apply(this,[index, keepExisting, preventViewNotify]);
return true;
}else{
return false;
}
},


and modified the private function onMouseDown who's handle the click on the checkbox , handleMouseDown, selectRangeChecked

*Red mark where had change

onMouseDown


onMouseDown : function(e, t){
if(t.className && t.className.indexOf('x-grid3-cc-'+this.id) != -1){
e.stopEvent();
// Define variables
var view = this.grid.getView();
var rowIndex = view.findRowIndex(t);
var record = this.grid.store.getAt(rowIndex);
var isSelected = this.isSelected(rowIndex);
var isChecked = record.data[this.dataIndex];
// Logic to select/de-select rows and the checkboxes
if(!this.email || this.alwaysSelectOnCheck){
if (isSelected){
if(!isChecked && this.alwaysSelectOnCheck){
this.toggleChecked(rowIndex, true);
}
else{
this.deselectRow(rowIndex);
this.toggleChecked(rowIndex, false);
}
}
else{
if(this.selectRow(rowIndex, true)){
this.toggleChecked(rowIndex, true);
view.focusRow(rowIndex);
}
}
}
else{
if (isChecked){
this.toggleChecked(rowIndex, false);
}
else{
this.toggleChecked(rowIndex, true);
}
}
view.focusRow(rowIndex);
}
// Load the state manager
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
Ext.state.Manager.loaded = true;
},


handleMouseDown function


handleMouseDown : function(g, rowIndex, e){
var t = e.getTarget('.ux-row-action-item');
if(!t) {
if(e.button !== 0 || this.isLocked()){
return;
};
var view = this.grid.getView();
var record = this.grid.store.getAt(rowIndex);
if(e.shiftKey && this.last !== false){
var last = this.last;
this.selectRange(last, rowIndex, e.ctrlKey);
if(!this.email){ this.selectRangeChecked(last, rowIndex, e.ctrlKey); }
this.last = last; // reset the last
view.focusRow(rowIndex);
}else{
var isChecked = record.data[this.dataIndex];
var isSelected = this.isSelected(rowIndex);

if (isSelected){
this.deselectRow(rowIndex);
if(!this.email){ this.toggleChecked(rowIndex, false); }
}else{
if(!this.excel){

if(!this.email && this.selectRow(rowIndex, true)){
this.toggleChecked(rowIndex, true);
}
}
else{

if(!this.email && this.selectRow(rowIndex, e.ctrlKey)){
this.selectRangeChecked(rowIndex, rowIndex, e.ctrlKey);
}
}
view.focusRow(rowIndex);
}
}
}
}


selectRangeChecked


selectRangeChecked : function(startRow, endRow, keepExisting){
if(this.locked) return;
if(!keepExisting){
if(!this.email || this.alwaysSelectOnCheck){ this.clearSelections(); }
this.clearChecked();
}
if(startRow <= endRow){
for(var i = startRow; i <= endRow; i++){
if(this.grid.store.getAt(i)){
if(!this.email || this.alwaysSelectOnCheck){
if(this.selectRow(i, true)){
this.toggleChecked(i, true);
}
}else{
this.toggleChecked(i, true);
}
}
}
}
else{
for(var i = startRow; i >= endRow; i--){
if(this.grid.store.getAt(i)){
if(!this.email || this.alwaysSelectOnCheck){
if(this.selectRow(i, true)){
this.toggleChecked(i, true);
}
}else{
this.toggleChecked(i, true);
}
}
}
}
},


I tested the code, but NoahK17 try it a little more, I think there maybe some changes in the select with arrows.

Ops, I've forgot! I make some changes to your extension, can I? :) if not, sorry.

Edit:
Sorry, one problem remain, when selected an row, the event beforerowselect occurs more than once. (I don't know how I will make the selectRow in Ext not execute.)

NoahK17
26 Jun 2008, 11:20 AM
Of course, bug fixes are always welcome. I'll add your code to my own project and play around with it a bit. Cheers! :)

brenda
30 Jun 2008, 7:34 PM
This is great :) I've solved my problem with this... Now I have a little problem..
When I want to have a header, the checkbox image still appear :( like this:
http://img103.imageshack.us/img103/3589/checkboxappearedkj8.jpg

Anyone encounter this problem? I saw this on both FF2 and IE6 browsers

NoahK17
1 Jul 2008, 10:02 AM
Use the latest version (1.7) and make sure the header you send in looks something like this:


<div id="x-grid3-hd-checker">&nbsp;Ref</div>

Cheers!

yaroslav
1 Jul 2008, 2:22 PM
Thanks a lot!
Very nice extension.

brenda
1 Jul 2008, 9:26 PM
Use the latest version (1.7) and make sure the header you send in looks something like this:


<div id="x-grid3-hd-checker">&nbsp;Ref</div>

Cheers!
Thnx Noah :)
I've followed your advice and customise the CSS a little with 2 images that I've split from the original one (row-check-sprite.gif) to obtained the following output:
http://img354.imageshack.us/img354/7594/checkboxappearedsolvedph0.jpg

I've attached the little CSS codes that I've customised and the images:


.x-grid3-hd-checker{
background-image:url(../images/row-check-sprite-uncheck.gif);
background-position:23px 1px;
}

.x-grid3-hd-checker-on .x-grid3-hd-checker{
background-image:url(../images/row-check-sprite-check.gif);
background-position:23px 1px;
}

nb
13 Jul 2008, 11:21 PM
hi,

I have used this smartcheckboxselectionmodel and i need something like below..plz tell how to do that..

I need to catch event listeners when i select a row and another event listeners when i check the checkbox(as well as when i uncheck)...if i use something like that
listeners:{rowselect:myFunctionOnSelect} , then both rowselect and checkbox check call the same function. how can i detect if it is row select or checkbox check?

I have configuration email:true.

NoahK17
14 Jul 2008, 7:25 AM
I see what you mean. Give me a few hours and I'll post an update that will suit your needs. Cheers!

imnphd
17 Jul 2008, 7:57 AM
Any ideas how can I make the Ext.grid.SmartCheckboxSelectionModel work using a remoteSort in the data store? Seems to me that I either have to send (via ajax) the status of a checkbox every time I check/uncheck or save the state of the of box using a unique id for the checked boxes....... or :-?
Thanks you.
Isaac

NoahK17
17 Jul 2008, 8:02 AM
If there is no paging, then using a remote sort should work out of the box. When you throw paging into the mix, you either have to use a Cookie/HTTP provider, and/or save the state of the checkboxes as they are clicked, and if that's done, you can comment out one or two lines in the SelectionModel to properly check the boxes again based on the store data.

I could help you out with that part if you go that route... or if you come up with another method, I'd love to add your code to the SelectionModel :)

@nb: Haven't had time yet to complete your request, but it's on my TODO list this week. Cheers!

imnphd
17 Jul 2008, 8:15 AM
I also need paging (I have ~56000 rows) so the idea of a Cookie/HTTP sounds the way to go. Let me know once you get the chance to implement it.
Thanks again.
Isaac

imnphd
18 Jul 2008, 4:51 AM
How can you identify each row? If you have a column in your data that is unique then there is no problem otherwise ..... :-? hmmm...
Isaac

mystix
18 Jul 2008, 8:40 AM
How can you identify each row? If you have a column in your data that is unique then there is no problem otherwise ..... :-? hmmm...
Isaac
store the page no. somewhere.
all that's needed then to uniquely identify a row (without the need for ids), assuming your sort order doesn't change, would be this formula:


var virtualRowId = (pageNo * pageSize) + rowNo;

imnphd
18 Jul 2008, 9:05 AM
That ain't gonna work as you said if you sort the grid.
Isaac

mystix
18 Jul 2008, 9:19 AM
That ain't gonna work as you said if you sort the grid.
Isaac
duh. 8-|
it's a mere alternative in the unfortunate event you don't have unique row ids.

if you dislike that you could md5 all Fields in a Record and use that as a row id.
and again the new assumption would be that none of the Fields are mutable.

imnphd
18 Jul 2008, 11:18 AM
Can you do md5 in Javascript?. If you need to do it in the server then what is the purpose since you would have all the info needed in the server to identify your record.
Isaac

mystix
18 Jul 2008, 11:27 AM
Can you do md5 in Javascript?.
md5 is just another algo, so yes you can. in fact, there's an extension by @wm003 for this:
http://extjs.com/forum/showthread.php?p=133516#post133516


If you need to do it in the server then what is the purpose since you would have all the info needed in the server to identify your record.
Isaac
wasn't your original question about how to identify a row (albeit without any info i.e. id from the server)?

How can you identify each row? If you have a column in your data that is unique then there is no problem otherwise ..... :-? hmmm...
Isaac
that's what i was responding to, so if i've misunderstood your question let me know.

imnphd
18 Jul 2008, 12:30 PM
Now that you ask... My original question was how to implement a check box in a grid that has paging. In everything that I have tried so far, I lose the state of the checkbox once I go to another page. What do you think would be the simplest way to accomplish it?
Thank you.
I

imnphd
22 Jul 2008, 7:15 AM
Here is a side server solution for the paging issue.

First, the side server script needs to take care of accepting a parameter to check a single row, all the rows or un-check all the rows. In our case we pass a parameter named 'check' whose value can be either a row index, 'all' or 'none'. We also need to pass all the parameters used to display the data so we can identify each row in the server. Once this is done the server just need to pass the boolean value for each row, that is checked=true or checked= false. Here are some pieces of code that could be plug in in the checkBoxSelectionModel. We also have a perl script that handles the server side if anybody is interested.



Ext.grid.CustomCheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {
header: '<div class="x-grid3-hd-checker"> </div>',
width: 20,
sortable: false,
menuDisabled:true,
fixed:true,
dataIndex: '',
id: 'checker', initEvents : function(){
Ext.grid.CustomCheckboxSelectionModel.superclass.initEvents.call(this);
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
Ext.fly(view.innerHd).on('mousedown', this.onHdMouseDown, this);
this.grid.getStore().on('load',this.onStoreLoad, this);
this.onGridRender(this.grid.getStore());
}, this);
},

onMouseDown : function(e, t){
if (e.button === 0 && t.className == 'x-grid3-row-checker'){
e.stopEvent();
var row = e.getTarget('.x-grid3-row');
if (row) {
var index = row.rowIndex;
var params = this.grid.getStore().lastOptions.params;
Ext.Ajax.request({
url:this.grid.getStore().proxy.conn.url,
scope: this,
method:'post',
params:Ext.apply(params, {check: index}),
success: function (transport) {
var response = Ext.decode(transport.responseText);
if (response == 1) {
if (this.isSelected(index)) {
this.deselectRow(index);
} else {
this.selectRow(index, true);
}
delete(this.grid.getStore().lastOptions.params['check']);
} else {
alert('A problem occurred while saving check information on server.');
}
},
failure: function (transport) {
alert('A problem occurred while communicating with the server.\n'+transport.responseText);
}
});
}
}
},

onHdMouseDown : function(e, t){
if (t.className == 'x-grid3-hd-checker') {
e.stopEvent();
var hd = Ext.fly(t.parentNode);
var params = this.grid.getStore().lastOptions.params;
var isChecked = hd.hasClass('x-grid3-hd-checker-on');
Ext.MessageBox.show({
title: 'Please wait',
msg: 'Updating...',
width:200,
wait:true,
animEl: 'update_wait'
});
Ext.Ajax.request({
url:this.grid.getStore().proxy.conn.url,
method:'post',
scope: this,
params:Ext.apply(params, {check: (isChecked == true ? 'none' : 'all')}),
success: function(transport){
var hd = Ext.fly(t.parentNode);
var isChecked = hd.hasClass('x-grid3-hd-checker-on');
var response = Ext.decode(transport.responseText);
if (response == 1) {
if (isChecked == true) {
hd.removeClass('x-grid3-hd-checker-on');
this.clearSelections();
} else {
hd.addClass('x-grid3-hd-checker-on');
this.selectAll();
}
Ext.MessageBox.hide();
delete(this.grid.getStore().lastOptions.params['check']);
} else {
alert('A problem occurred while saving check information on server.');
}
},
failure: function(transport){
alert('A problem occurred while communicating with the server.\n'+transport.responseText);
}
});
}
},

onStoreLoad: function(store, recs, options){
for (var i=0;i<recs.length;i++) {
if (recs[i].get('checked') == true) {
this.selectRow(i, true);
}
}
},

onGridRender: function(store){
var totalCount = store.getCount();
for (var i=0;i<totalCount;i++) {
if (store.getAt(i).get('checked') == true) {
this.selectRow(i, true);
}
}
},

renderer : function(v, p, record){
return '<div class="x-grid3-row-checker"> </div>';
}

});

NoahK17
22 Jul 2008, 7:27 AM
So basically, as you are clicking around, you are saving the checked state to the server. Which of course would work with paging using my Smart CheckboxSelectionModel.

I suppose I might be able to add that type of functionality to the code, I was just trying to reduce the amount of server-calls issued throughout the experience.

nb
23 Jul 2008, 8:32 PM
hi,

I have used this smartcheckboxselectionmodel and i need something like below..plz tell how to do that..

I need to catch event listeners when i select a row and another event listeners when i check the checkbox(as well as when i uncheck)...if i use something like that
listeners:{rowselect:myFunctionOnSelect} , then both rowselect and checkbox check call the same function. how can i detect if it is row select or checkbox check?

I have configuration email:true.

//----------------

hello Noah ..
have u found any solution of this problem ???

nb

Nalfein
28 Jul 2008, 6:40 AM
After I switched to use StartCheckBoxSelectionModel my grid's "rowdblclick" handler stopped being called. Is there any way to make it work?

NoahK17
28 Jul 2008, 6:41 AM
After I switched to use StartCheckBoxSelectionModel my grid's "rowdblclick" handler stopped being called. Is there any way to make it work?Were you using the RowSelectionModel before with the "rowdblclick" handler?

Nalfein
28 Jul 2008, 8:52 AM
Were you using the RowSelectionModel before with the "rowdblclick" handler?

Yes, but I've checked with the standard CheckboxSelectionModel and it worked. With SmartCheckboxSelectionModel it doesn't work.

nb
29 Jul 2008, 4:23 AM
//----------------

hello Noah ..
have u found any solution of this problem ???

nb


hi,

I have used this smartcheckboxselectionmodel and i need something like below..plz tell how to do that..

I need to catch event listeners when i select a row and another event listeners when i check the checkbox(as well as when i uncheck)...if i use something like that
listeners:{rowselect:myFunctionOnSelect} , then both rowselect and checkbox check call the same function. how can i detect if it is row select or checkbox check?

I have configuration email:true.

I have found my solution in one way..
At first u have to add a event on ur store update like
grid2.store.on('update', function(thestore, record, operation){ }
if u have email:true then when u select a row then rowselect event will be fired but checkbox will not be selected.
And when u check the checkbox then the store update event will fire but no row will be selected and rowSelect event will not fire.

cheers.......

nb
29 Jul 2008, 9:10 PM
hi Noah Kronemeyer,

how can i show and check/uncheck 2 different check box column in one grid.
the 2 checkbox column data will come from 2 different dataIndex.Its possible.
But which SmartCheckboxSelectionModel will be the sm(that is selection model) of grid.
Actually, only one can be sm.But if i have 2 checkbox column then i need 2 sm, isn't it ??



var sm = new Ext.grid.SmartCheckboxSelectionModel({width:20,header:'', dataIndex: 'checked',email:true });
var sm2 = new Ext.grid.SmartCheckboxSelectionModel({width:20, header:'',dataIndex: 'checked2' ,email:true});

var grid2 = new xg.GridPanel({
....................................,
cm: new xg.ColumnModel([
sm,sm2,
......................................................]),
sm : sm,
................

imnphd
31 Jul 2008, 7:32 AM
Have you tried to use your SmartCheckBoxSelectionModel with the Ext.ux.LiveGrid (http://code.google.com/p/ext-ux-livegrid/) (http://code.google.com/p/ext-ux-livegrid/)
It would be very nice if they work together.
Isaac

Gams
6 Aug 2008, 2:07 AM
Thanks so much for this plugin its exactly what Ive been looking for.

But there is one thing Im having difficulty with. Ive implemented this on my editable grid where you can double click on certain cells to edit them. After using this plugin im unable to double click to edit. How can I get this to work?

Gams
6 Aug 2008, 6:19 AM
Thanks so much for this plugin its exactly what Ive been looking for.

But there is one thing Im having difficulty with. Ive implemented this on my editable grid where you can double click on certain cells to edit them. After using this plugin im unable to double click to edit. How can I get this to work?

I have just tested this on IE7 and is working fine. Its only on Firefox that its not allowing me to double click to edit the field.

foreigner42
15 Aug 2008, 9:07 PM
Where do I download SmartCheckBoxSelectionmodel from?

irwinm
19 Aug 2008, 11:18 AM
hi Noah Kronemeyer,

how can i show and check/uncheck 2 different check box column in one grid.
the 2 checkbox column data will come from 2 different dataIndex.Its possible.
But which SmartCheckboxSelectionModel will be the sm(that is selection model) of grid.
Actually, only one can be sm.But if i have 2 checkbox column then i need 2 sm, isn't it ??



var sm = new Ext.grid.SmartCheckboxSelectionModel({width:20,header:'', dataIndex: 'checked',email:true });
var sm2 = new Ext.grid.SmartCheckboxSelectionModel({width:20, header:'',dataIndex: 'checked2' ,email:true});

var grid2 = new xg.GridPanel({
....................................,
cm: new xg.ColumnModel([
sm,sm2,
......................................................]),
sm : sm,
................


Anybody have any idea how to do this? Can we add 2 selection models for one grid panel?

I'm need to do the same thing as described in the quote and I have been unsuccessfully trying to find a solution for a couple of days now.

pkmiec
26 Aug 2008, 10:49 PM
Thanks for making the SmartCheckboxSelectionModel. It is awesome.

I'm trying to use it with a EditorGridPanel (in FF3) with clickToEdit = 1. It seems if email option is true, things work ... however, if email option is false, none of the cells start editing. When email option is false, toggleChecked is called which set's the selected value on the record. Somehow that causes the event to get eaten up (maybe a browser problem).

After a while I took a different approach and decided to skip selecting / checking if the user clicks on a cell that is editable. Perhaps others would find this behavior useful as well. I implemented it as follows, but maybe there is a better way:



handleMouseDown : function(g, rowIndex, e){
var cell = g.getView().findCellIndex(e.getTarget());
var row = g.getView().findRowIndex(e.getTarget());
if (cell != null && row != null && g.getColumnModel().isCellEditable(cell, row)) {
return;
}

...
}

spsenthilraja
31 Aug 2008, 8:48 PM
Very nice...:) is there any working example for this smart work?

Gams
9 Sep 2008, 2:30 AM
I am trying to figure out a way of detecting when a user selects a checkbox not just the row.

I have a grid which has a list of items generated from a database. On selecting a row or checkbox that item will be updated in the database and the grid reloaded. When the grid reloads the checkbox is selected but the row wasn't highlighted/selected. So when trying to uncheck the checkbox you have to click it twice.. the first time you click it, it selects the row and then second time you are able to uncheck the checkbox.

I figured out a way of selecting the rows when the grid is reloaded..


myData.on('load', function(p){

var dataIndex = sm.grid.getSelectionModel().dataIndex; // the dataIndex for the selectionModel
var count = sm.grid.store.getCount();
//alert(count);
for(var i = 0, len = count; i < len; i++){
var dataIndexValue = p.data.items[i].data[dataIndex]; // the value of the dataIndex for each row
var isSelected = sm.isSelected(i);

var record = sm.grid.store.getAt(i);
var isChecked = record.data[sm.dataIndex];

if (isChecked && !isSelected){
sm.selectRow(i, true);
}
}

..this then enabled me to uncheck boxes on one click but now the function i have for updating items and reloading the grid keeps firing because the above code goes through every row that was previously selected. I just want to run the grid to load with all items selected that are checked and any new row that the user selects or checks run the function.

Any help will be much appreciated.. thanks

innovator
16 Sep 2008, 3:24 AM
Ext.get('x-grid3-hd-checker') is returning null to me. any reason.

galdaka
22 Sep 2008, 11:21 PM
Hi,

Is posible remember selections by cookies? I supose that each row have a unique ID.

Is posible live demo?

Thanks in advance,

Eric24
28 Sep 2008, 7:41 PM
Do you happen to know if your Smart CheckboxSelectionModel solves the standard CheckboxSelectionModel's "conflict" with drag-and-drop? (See the thread http://www.extjs.com/forum/showthread.php?p=200791).

NoahK17
29 Sep 2008, 7:19 AM
Do you happen to know if your Smart CheckboxSelectionModel solves the standard CheckboxSelectionModel's "conflict" with drag-and-drop? (See the thread http://www.extjs.com/forum/showthread.php?p=200791).

Eric: The Smart CBSM is an extension of RowSelectionModel, so any "bugs" as described in the thread referenced will more than likely exist in my version.

But as far as I know, there is no "we are dragging something" mouse event in the Javascript DOM. There's mouseup, mousedown, and the such. But no "mousedrag". The drag/drop works with mouseup and mousedown... as would "clicking", because it fires either/or of those two events.

I do like the "clicking a checkbox checks stuff" and clicking a row drags stuff. But what about clicking a row to check a checkbox? How will the browser know the difference?

NoahK17
29 Sep 2008, 7:29 AM
Ext.get('x-grid3-hd-checker') is returning null to me. any reason.

Make sure your header looks like: header: '<div id="x-grid3-hd-checker" class="x-grid3-hd-checker"> </div>',

Eric24
29 Sep 2008, 7:42 AM
Too bad--I was hoping for a quick fix ;)

I understand that there is no "dragging" event. I was originally thinking that the difference between a click ("down, up") and a drag ("down, move, up") would be enough to tell the difference between the two, but in thinking it over, I suppose that most click actions would happen immediately on the "down".

What about this: As I understand it, it is the whole row that is being dragged, so the problem comes about because the checkbox is "on/in" the row. Would it not be possible to "carve out" the area around occupied by the checkbox so that a click here isn't picked up by the drag logic? As I see it, the only downside is that you can't drag a row by "grabbing" it by its checkbox, which I don't see as much of a problem anyway. Can you think of any reason why this couldn't be done?

michaelc
29 Sep 2008, 11:47 AM
I am having one minor issue with the SmartCheckboxSelectionModel.
the initial value of all check boxes is checked reguardless of the dataIndex value.

in firebug I stopped it in the render function and values of true and false were being passed but all check boxes were checked.

any idea what I may have done incorrectly ?




QoDesk.Schedule = Ext.extend(Ext.app.Module, {

moduleType : 'demo',
moduleId : 'if-da-schedule',

init : function() {
this.launcher = {
handler : this.createWindow,
iconCls : 'icon-grid',
scope : this,
shortcutIconCls : 'demo-grid-shortcut',
text : 'Data Access Scheduler',
tooltip : '<b>Data access acheduler</b><br />Data access scheduler'
}
},

createWindow : function() {
var desktop = this.app.getDesktop();
var win = desktop.getWindow('if-da-schedule');
var ds = new Ext.data.Store({
reader : new Ext.data.ArrayReader({}, [{
name : 'application'
}, {
name : 'id'
}, {
name : 'type'
}, {
name : 'userName'
}, {
name : 'userEmail'
}, {
name : 'nextDate'
}, {
name : 'frequency'
}, {
name : 'status'
}, {
name : 'action'
}]),
data : Ext.grid.dummyData
})

if (!win) {
var sm = new Ext.grid.SmartCheckboxSelectionModel({
dataIndex:'action',
email : true, // separates checkbox clicking from row
// selecting
alwaysSelectOnCheck : true
});

var grid = new Ext.grid.GridPanel({
autoExpandColumn : 'company',
border : false,
store : ds,
cm : new Ext.grid.ColumnModel([sm, {
header : "Schedule Name",
width : 70,
sortable : true,
dataIndex : 'application'
}, {
header : "Data Access",
width : 70,
sortable : true,
dataIndex : 'type'
}, {
header : "Created by",
width : 70,
sortable : true,
dataIndex : 'userName'
}, {
header : "Last Run",
width : 100,
sortable : true,
dataIndex : 'nextDate'
}, {
header : "Frequency",
width : 100,
sortable : true,
dataIndex : 'frequency'
}, {
header : "Status",
width : 70,
sortable : true,
dataIndex : 'status'
}, {
header : "Action",
width : 70,
sortable : true,
dataIndex : 'action'
}]),
shadow : false,
shadowOffset : 0,
// plugins : checkColumn,
sm : sm,
tbar : [{
text : 'Add',
tooltip : 'Add a new Schedule',
iconCls : 'demo-grid-add'
}, '-', {
text : 'Remove',
tooltip : 'Remove a selected Schedule',
iconCls : 'demo-grid-remove',
listeners : {
click : function(c) {
ds = this.deleteRows(ds);
},
scope : this
}
}, '-', {
text : 'Modify/View',
tooltip : 'Modify or Review a selected Schedule',
iconCls : 'demo-grid-a'
}],
viewConfig : {
forceFit : true
}
});

var taskbarEl = Ext.get('ux-taskbar');
var winWidth = (Ext.lib.Dom.getViewWidth() - 4);
var winHeight = (Ext.lib.Dom.getViewHeight() - (taskbarEl
.getHeight() + 4));
win = desktop.createWindow({
id : 'if-da-schedule',
title : 'Data access schedule',
width : winWidth,
height : winHeight,
iconCls : 'icon-grid',
shim : false,
animCollapse : false,
constrainHeader : true,
layout : 'fit',
items : grid,
taskbuttonTooltip : '<b>Data access acheduler</b><br />Data access scheduler'
});

}

win.show();
},
deleteRows : function(ds) {
// find selected rows and remove them from the store
var count = ds.getCount();
for (i = count - 1; i >= 0; i--) {
var record = ds.getAt(i);
var data = record.get('action');
if (data) {
ds.remove(record);
}
}
return ds;
}
});

// Array data for the grid
Ext.grid.dummyData = [
['Terminal-pc', 340, 'Data', 'Sam Sur', 'sam.sur@hitachi-hta.com',
'Thursday 9/1 12:00am',
'Weekly: every 2 weeks on: Monday, Wensday, Friday', 'Active',
'true'],
['i-Recipe', 341, 'Data', 'Sam Sur', 'sam.sur@hitachi-hta.com',
'Thursday 9/1 12:00am', 'Monthly: 18th of every 4 month ',
'Active', 'true'],
['i-Metri', 342, 'Data', 'Sam Sur', 'sam.sur@hitachi-hta.com',
'Thursday 9/1 12:00am', 'Monthly: 18th of every 4 month ',
'Suspended', 'false'],
['Terminal-pc', 343, 'Data', 'Michael C Ford',
'Michael.Ford@hitachi-hta.com', 'Thursday 9/1 12:00am',
'Weekly: every 2 weeks on: Monday, Wensday, Friday', 'Active',
'true'],
['i-Recipe', 344, 'Data', 'Michael C Ford',
'Michael.Ford@hitachi-hta.com', 'Thursday 9/1 12:00am',
'Monthly: 18th of every 4 month ', 'Active', 'false'],
['i-Metri', 345, 'Data', 'Michael C Ford',
'Michael.Ford@hitachi-hta.com', 'Thursday 9/1 12:00am',
'Monthly: 18th of every 4 month ', 'Suspended', 'true'],
['Terminal-pc', 343, 'Data', 'Amit Parikh',
'Amit.Parikh@hitachi-hta.com', 'Thursday 9/1 12:00am',
'Weekly: every 2 weeks on: Monday, Wensday, Friday', 'Active',
'false'],
['i-Recipe', 344, 'Data', 'Amit Parikh', 'Amit.Parikh@hitachi-hta.com',
'Thursday 9/1 12:00am', 'Monthly: 18th of every 4 month ',
'Active', 'true'],
['i-Metri', 345, 'Data', 'Amit Parikh', 'Amit.Parikh@hitachi-hta.com',
'Thursday 9/1 12:00am', 'Monthly: 18th of every 4 month ',
'Suspended', 'true']];

NoahK17
30 Sep 2008, 10:29 AM
Hey Michael, I replied in your other thread. I'll have to try your code and see what I can come up with. I'm sure it's something simple we can do to fix the issue. :)

Rothariger
30 Sep 2008, 11:27 AM
hello,

does anyone knows if theres a way to know if the check all is checked?

thanks!

NoahK17
30 Sep 2008, 2:34 PM
This fn determines if the "check all" checkbox on the header is checked or not:



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');
if(!this.email || this.alwaysSelectOnCheck){ this.clearSelections(); }
this.clearChecked(true); // the true param enables fast mode
}else{
hd.addClass('x-grid3-hd-checker-on');
if(!this.email || this.alwaysSelectOnCheck){ this.selectAll(); }
this.selectAllChecked(true);
}
}
// Load the state manager
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
Ext.state.Manager.loaded = true;
},

Rothariger
1 Oct 2008, 4:44 AM
yes i already see that, but i dont know how to get "t"...

michaelc
1 Oct 2008, 9:37 AM
minor bug I noted.
if I use the arrow keys to move up and down it moves by 2 rows vs 1 row.
also I would think that the enter key should toggle the selection.

NoahK17
1 Oct 2008, 10:18 AM
Hi Michael. Sounds like an implementation problem with conflicting code. If you look carefully, I have a piece of code which prevents the behavior you described:



// Disable the rowNav created in our parent object, otherwise pressing DOWN will go down two rows!
this.rowNav.disable();

If for whatever reason, the standard rowNav from RowSelectionModel is not being disabled, or if you have it renamed somewhere, then you will get the 2 rows vs. 1 row selection change when pressing up and down.

Good luck.

bluefox
2 Oct 2008, 8:11 PM
Hi I'm trying out your great extension but I'm wondering if there is any way we can store the user selection states so the selection will persist between refreshes? If so, what's the correct order of making it work? Thanks for your help!

Regards,

sambar
16 Oct 2008, 1:10 PM
Sorry I am new to EXT JS.

I really like this extension and i got it to work when i added the extension on to my JS File (which has the form that includes grid) but instead of including this code in all the files individually, can i just insert this code in a separate file (extension.js) and include it like the ext-base file ? Please help

patrosmania
23 Oct 2008, 6:03 AM
Hi, first of all thanks for the great work.
I used it in a grid with a paging bar, but every time i change the page and come back, the selections i made are gone. Is there any special line i should write in the grid?
Thans in advance.

mysticav
10 Nov 2008, 10:08 PM
I tried to deselect all rows, but found the following problems:

Using clearChecked without no fast argument, didn't work at all.

Setting argument "fast" to true, worked, but only unchecks, does not deselect the row.

I wonder if there a way to clear the checkbox and also deselect the row,

I can accomplish that calling to methods.


sm.clearChecked(true);
sm.clearSelections();

It will be nice if the author overrides the clearSelections(), adding an argument to also uncheck the checkboxes.

I would just need to call:

sm.clearSelections(true);

mysticav
11 Nov 2008, 11:38 PM
If there's only 1 row in the grid, using "excel" config option,
The rowselect event is fired twice!

Can sombody help me fix this problem ?

yosituno
13 Nov 2008, 9:04 AM
First of all, thanks for this extension. Regrettably, when paginating the previously selected items are not preserve. To reproduce do this:

* select on item on page.
* then go to the next page and select another item.
* Now, go eithe prev or next page.
* Expected results: the previously selected items should be remembered.
Actual results: the grid does not remember the previously selected items


Any thoughts?

mcouillard
13 Nov 2008, 10:22 AM
when paginating the previously selected items are not preserved

This is a critical shortcoming for my project, too. Paging is done remotely in our case but it seems logical that EXT would keep a log of the row IDs and what was checked. It would then use this cache of checkmarks when showing subsequent rows.

raption83
24 Nov 2008, 12:10 AM
I just downloaded SmartCheckboxSelectionModel. I was testing it on ExtJS 2.2 and realise a adnormal behavior.

When i click on the Select All/Unselect All checkbox located on the header of the grid, all the checkboxes get checked/unchecked but after completion, it will focus on the last row. If running on Firefox with Firebug on, you can see it focusing on the checkbox and checking/unchecking it. I think this is the reason why it ends up focusing on the last row.

I tried in on ExtJS 2.1, this behavior did not show.

largerain
4 Dec 2008, 11:52 PM
My problem is solved now.
If you use inline data for your store (i.e. 'data' config parameter) the selectionmodel won't be attached to 'load' event listeners yet. Thus, no rows will be actually selected.
The solution is like


mygrid.on('render', function () {
this.getStore().loadData(mydata)
})


When the page initialize,I fix the second click problem.But the backgroud colour of the checked row is not changed.How to get the selected row colour effect by initialization?(eg:http://extjs.com/forum/attachment.php?attachmentid=7260&d=1212682954)(:|,thanks.


Ext.onReady(function(){
var data = [[true,1, 'EasyJWeb', 'EasyJF', 'www.easyjf.com'],
[true,2, 'jfox', 'huihoo', 'www.huihoo.org'],
[true,3, 'jdon', 'jdon', 'www.jdon.com'],
[false,4, 'springside', 'springside', 'www.springside.org.cn']];
var store = new Ext.data.SimpleStore({
data: data,
fields: ["checked","id", "name", "organization", "homepage"]
});
var sm = new Ext.grid.SmartCheckboxSelectionModel({
header:false,
dataIndex:'checked'
// , email: false
});
var grid = new Ext.grid.GridPanel({
id:'mygrid',
title: "grid",
height: 150,


stripeRows:true,
enableColumnResize : true,
viewConfig: {
autoFill:true
},
columns: [sm,{
header: "first",
dataIndex: "name",
id:"proname",
sortable: true,
autoWidth:true
}, {
header: "second",
sortable: true,
dataIndex: "organization",
autoWidth:true

}, {
header: "address",
sortable: true,
dataIndex: "homepage",
autoWidth:true
}],
store: store,
sm: sm,
listeners: {
render: function(ss){
ss.getStore().loadData(data);
}
}
});

var viewport = new Ext.Viewport({
layout: 'border',
height: 300,
items: [{
region:'center',
height: 300,
id: 'logmenu',
title: 'grid',
items: grid
}]
});
});

NoahK17
5 Dec 2008, 9:33 AM
Remember, the checkbox selection is seperate from the row selection. It's been a while since I played around w/ the code as I haven't had any use for it recently, but what happens when email is set to false? (I see it commented out above)

NoahK17
5 Dec 2008, 9:34 AM
Sorry I am new to EXT JS.

I really like this extension and i got it to work when i added the extension on to my JS File (which has the form that includes grid) but instead of including this code in all the files individually, can i just insert this code in a separate file (extension.js) and include it like the ext-base file ? Please help

That's exactly how it works, yes. Just make sure extension.js is called BEFORE your other .js files.

largerain
5 Dec 2008, 5:58 PM
Remember, the checkbox selection is seperate from the row selection. It's been a while since I played around w/ the code as I haven't had any use for it recently, but what happens when email is set to false? (I see it commented out above)
I uncommented the ", email: false".Result is the same.Colour doesn't change.....:(

largerain
7 Dec 2008, 7:47 PM
Remember, the checkbox selection is seperate from the row selection. It's been a while since I played around w/ the code as I haven't had any use for it recently, but what happens when email is set to false? (I see it commented out above)
I see
"email: if set to true, the checking of a checkbox and the selecting of a row will be separated out.",That means:If I set to false,the checking of a checkbox and the selecting of a row will be binded together? So I can get the selected row colour by initialization?:-?

dmcclure
9 Dec 2008, 1:12 PM
First, great component NoahK17, many thanks!

Problem:
The grid scrolls from top to bottom whenever the header checkbox is selected. Basically, as each checkbox is either checked or unchecked the row being modified is made the current row (guessing through call to grid.getView().focusRow()??). I've traced the calls in SmartCheckboxSelection to be:

onHdMouseDown() -> selectAllChecked() or clearChecked() -> toggleChecked() -> record.set() -> store.afterEdit() -> this.fireEvent("update"...)

As soon as the fireEvent call is processed, the row is made the current row in focus. Can't seem to find the handler for this event to see where the focusRow() call is made.

Would like to prevent this behaviour from occurring so if someone could steer me in the right direction it would be greatly appreciated.

dmcclure
10 Dec 2008, 8:04 AM
First, great component NoahK17, many thanks!

Problem:
The grid scrolls from top to bottom whenever the header checkbox is selected. Basically, as each checkbox is either checked or unchecked the row being modified is made the current row (guessing through call to grid.getView().focusRow()??). I've traced the calls in SmartCheckboxSelection to be:

onHdMouseDown() -> selectAllChecked() or clearChecked() -> toggleChecked() -> record.set() -> store.afterEdit() -> this.fireEvent("update"...)

As soon as the fireEvent call is processed, the row is made the current row in focus. Can't seem to find the handler for this event to see where the focusRow() call is made.

Would like to prevent this behaviour from occurring so if someone could steer me in the right direction it would be greatly appreciated.

Coworker resolved this issue by overriding the selectAllChecked function. Basically duplicated the original function but at the beginning of the function suspended the events on the grid store and then once the original code was completed, re-enabled the events on the store. Now, when the header checkbox is selected, all checkboxes are toggled but no scrolling occurs.

leonardo kenji
16 Dec 2008, 12:37 PM
Hi

first of all, thanks for this nice piece of code

I can't make it keep the selections. Attached goes the json and the html that includes the javascript calls.

Any help is welcome. Thanks.

Ballsacian1
28 Dec 2008, 1:08 PM
When using the SmarkCheckboxSelectionModel I noticed a lot of stuttering and other extremely strange issues that ended up being linked to calling record.set(). So I manually call it and manually change the classes as necessary. I noticed a huge improvement in speed. This includes initial load speed as well as the time it takes to uncheck / check lots of rows.

Hope this helps out.


toggleChecked : function(rowIndex, c){
//debugger;
if(this.locked) return;
var record = this.grid.store.getAt(rowIndex);
if(c === true){
// Check
//debugger;
// record.set(this.dataIndex, true); OLD CODE
// This avoids calling tons of events and weird lagging issues.
record.data[this.dataIndex] = true; // Fixes a huge lag bug.
var checkCol = Ext.select('.x-grid3-cc-'+this.id, false, this.grid.getView().getRow(rowIndex));
checkCol.addClass('x-grid3-check-col');
checkCol.addClass('x-grid3-check-col-on');

}
else if(c === false){
// Uncheck
// record.set(this.dataIndex, false); OLD CODE
// This avoids calling tons of events and weird lagging issues.
record.data[this.dataIndex] = false; // Fixes a huge lag bug
var checkCol = Ext.select('.x-grid3-cc-'+this.id, false, this.grid.getView().getRow(rowIndex));
checkCol.addClass('x-grid3-check-col');
checkCol.removeClass('x-grid3-check-col-on');

}
else{
// Toggle checked / unchecked
//record.set(this.dataIndex, !record.data[this.dataIndex]); OLD CODE
// This avoids calling tons of events and weird lagging issues.
record.data[this.dataIndex] = !record.data[this.dataIndex];
var checkCol = Ext.select('.x-grid3-cc-'+this.id, false, this.grid.getView().getRow(rowIndex));
checkCol.addClass('x-grid3-check-col'+(record.data[this.dataIndex]?'-on':''));
}

// tell everyone that the checkboxes changed
this.fireEvent("checkboxchange", this, record);

},

heavengrass
6 Jan 2009, 4:59 AM
I'm find it long time,thank you.

salvo
28 Jan 2009, 8:32 AM
Hi,

With config email:true and alwaysSelectOnCheck:false how to get the list of "checked" rows and not just "selected" rows?

var sm = new Ext.grid.SmartCheckboxSelectionModel({
email: true, // separates checkbox clicking from row selecting
excel: false,
alwaysSelectOnCheck: true
});
sm.getSelections() is no help in this case :-?

Thanks

junkzilla
28 Jan 2009, 9:11 AM
Hey. Great code here. I'm hoping for a new feature. I'd like to be able to use the checkmark column header as a sort header. It would first require removal of the checkALL checkmark, and replacing it with header text. Clicking it should pull all the checkmarked rows to the top or bottom of the row order. Essentially use the header as a numeric sort header. Does anyone have an idea on how to pull this off?

doxe
17 Feb 2009, 8:19 AM
Hi all,

Is there anybody here who have got some issues in IE7 with this great extension ?

I use it in a grid embedded in a window, it works just fine in FF, all my "checked" remote data are checked in the grid but in IE all rows stay unchecked...

Here is a piece of my code (truncated) :



var grids = {
equipments: function(callback, tariffId){
if (tariffId !== '') {
var loadUrl = '/administration/equipments/get-all-json/tariff/' + tariffId;
}
else {
var loadUrl = '/administration/equipments/get-all-json/tariff/';
}

if (typeof(Ext.getCmp('equipment-grid')) != 'undefined') {
var ds = Ext.getCmp('equipment-grid').getStore();
ds.proxy.conn.url = loadUrl;
ds.load();
}

if (!Ext.getCmp('equipment-dialog')) {
var scope = this;
this.callback = callback;
// create the data store
this.equipmentStore = new Ext.data.JsonStore({
url: loadUrl,
root: 'equipments',
autoLoad: false,
totalProperty: 'total',
fields: [{
name: 'checked',
type: 'bool'
}, {
name: 'Equipment_Type_id',
type: 'string'
}, {
name: 'Description',
type: 'string'
}, {
name: 'Abbreviation',
type: 'string'
}, {
name: 'ISO_Code',
type: 'string'
}]
});

// Create selection & column model
this.equipmentSelModel = new Ext.grid.SmartCheckboxSelectionModel({
dataIndex: 'checked',
email: true,
excel: false,
alwaysSelectOnCheck: true
});
this.equipmentColModel = new Ext.grid.ColumnModel([this.equipmentSelModel, {
header: getTranslatedText('description'),
sortable: true,
dataIndex: 'Description',
align: 'left'
}, {
header: getTranslatedText('abbreviation'),
sortable: true,
dataIndex: 'Abbreviation',
align: 'left'
}, {
header: getTranslatedText('code'),
sortable: true,
dataIndex: 'ISO_Code',
align: 'left'
}]);

// create the grid
this.equipmentGrid = new Ext.grid.GridPanel({
id : 'equipment-grid',
store: this.equipmentStore,
cm: this.equipmentColModel,
sm: this.equipmentSelModel,
viewConfig: {
forceFit: true
},
deferRowRender: false,
stripeRows: true,
autoExpandColumn: 'Description'
});

// Load datastore
this.equipmentStore.load();

// Create and/or open the dialog
this.equipmentDialog = new Ext.Window({
renderTo: document.body,
id : 'equipment-dialog',
constrain: true,
closeAction: 'hide',
layout: 'fit',
width: 880,
height: 570,
plain: true,
modal: true,
shadow: false,
items: this.equipmentGrid,
title: getTranslatedText('equipments_list'),
buttons: [{
text: getTranslatedText('add_checked_equipments'),
handler: function(){
var cs = scope.equipmentGrid.getSelectionModel();
var selections = cs.getSelections();
scope.callback(scope.equipmentStore.getCount(), selections);
scope.equipmentDialog.hide();
}
}, {
text: getTranslatedText('cancel'),
handler: function(){
scope.equipmentDialog.hide();
}
}]
});
Ext.WindowMgr.zseed = 9997;
}

this.equipmentDialog.show();
Ext.getCmp('equipment-dialog').doLayout();
}
(...)
}

Scorpie
17 Feb 2009, 11:44 PM
Nice plugin! Gonna test it out :)

mango
20 Feb 2009, 2:14 PM
Hi,

I am facing an issue Checkbox selection model "select/deselect all" header not working
. I tried both the checkboxselectionmodel and SmartCheckboxSelectionModel.

If I use checkboxselectionmodel , I am not able to select the header checkbox, and I can select only one row checkbox at a time.
With the SmartCheckboxSelectionModel, I am able to select the header checkbox but rows all the rows checkbox are not selected. And when I click on particular row checkbox, I am getting the following error:


record is undefined<br>onMouseDown()(Object browserEvent=Event mouseout button=0 type=mouseout, div.x-grid3-check-col)selectionmodel.js (line 382)
h()()ext-all-debug.js (line 1694)
getViewWidth()()ext-base.js (line 10)
[Break on this error] var isChecked = record.data[this.dataIndex];


In both the cases, I am able to select one row only.

The config for the SmartCheckboxSelectionModel is:

var sm = new Ext.grid.SmartCheckboxSelectionModel({
dataIndex:'checked',
email:true //also tried with setting false
});

and I added the sm to my column model and grid.

Please help me out :)

Thanks in advance.

--mango

NoahK17
24 Feb 2009, 1:24 PM
@mango: My code is based off the normal CheckboxSelectionModel, so if the base class isn't working for you, it would appear there is some sort of conflict with another mod you have installed. The header checkbox works perfectly in my code. Sorry :/

@doxe: I develop in Firefox 3. I have no clue as to why it won't work in IE7.

@Everyone Else: Sorry I haven't updated in a while. I'm not currently using the code in my job -- I'm focusing more on Forms and basic Grids these days... but if I ever need to use checkboxes again to select rows on a grid, I'll be sure to revisit this UX and post more updates.

jeanvincent
26 Feb 2009, 8:49 AM
Noah, or anybody else, is there a way to sort rows with the checkbox column? You click one time on the header, and all the selected rows would be on top, you click a second time, all the selected rows would be at the bottom. You see what I mean? Just a simple sort.

wertyk
5 Mar 2009, 12:28 AM
Hi all.
I have a problem witch header(global, general) checkbox. My aspx page contain 2 ExtJs grids, and each grid have checkbox (CheckboxSelectionModel). I load data only in first grid, but in second grid i drag records from first grid. When i select all records witch header checkbox and move in other grid, this header checkbox remains checked even if don't have records. How to verify contain grid a data or not and if not contain data uncheck header checkbox?
Image of my page and code in thread:
http://extjs.com/forum/showthread.php?t=61248

Is possible resolve my problem witch SmartCheckBoxSelectioModel?

hlzhang1982
8 Mar 2009, 8:25 AM
Hi,

With config email:true and alwaysSelectOnCheck:false how to get the list of "checked" rows and not just "selected" rows?

var sm = new Ext.grid.SmartCheckboxSelectionModel({
email: true, // separates checkbox clicking from row selecting
excel: false,
alwaysSelectOnCheck: true
});
sm.getSelections() is no help in this case :-?

Thanks

I met the same problem: how to get the list of "checked" rows and not just "selected" rows?
Thanks in advance.

renku
23 Mar 2009, 2:48 AM
I didn't find any way to catch the event of checking or unchecking the checkboxes, so I modified to SmartCheckboxSelectionModel code slightly to add event "check":



Ext.grid.SmartCheckboxSelectionModel = function(config){
this.addEvents(
/**
* @event check
* Fires when the checkbox is checked or unchecked.
* @param {SelectionModel} this
* @param {Number} rowIndex The checked row index
* @param {Ext.data.Record} r The checked record
* @param {Bool} checked The new checked value
*/
"check"
);
Ext.grid.SmartCheckboxSelectionModel.superclass.constructor.call(this, config);
};

Ext.extend(Ext.grid.SmartCheckboxSelectionModel, Ext.grid.RowSelectionModel, {

...

toggleChecked : function(rowIndex, c){
if (this.locked) {
return;
}

var record = this.grid.store.getAt(rowIndex);
var checked = (typeof c === "boolean") ? c : !record.data[this.dataIndex];

record.set(this.dataIndex, checked);
this.fireEvent("check", this, rowIndex, record, checked);
},

...

});

Maybe this will be helful to somebody. Or perhaps it could even be included to SmartCheckboxSelectionModel itself.

With thanks for the great selection model component,

Rene Saarsoo

fausastu
28 Mar 2009, 7:57 AM
Hi, guys.

The checkBoxSelectionModel seems not work with Editor grids : the getSelections method returns no data. While in a simple Grid, return the selected rows.

Have someone test this extension with Editor Grids?

Thanks in advance.

cwkhor
9 Apr 2009, 6:01 PM
Thanks for sharing such good thing.
However, I notice that the vertical scroll bar was not refreshed / resized accordingly when the windows was resized.

This behaviour was different from the original CheckboxSelectionModel.
Can anyone update on this?

mysticav
18 Apr 2009, 12:07 AM
How can I disable some checkboxes ?

Let's say I have 6 rows. I need to disable the last 3 rows. So the user can only check the first three.

Thanks.

blow
28 Apr 2009, 9:17 AM
First of all very nice PI exactly what i needed.

However i have a small issue of which i haven't seen any questions in this thread yet, so i wonder why i do have this problem :)

When the grid 'loads' it nicely checks the checkboxes, however when i submit my form ( in this case ). It doesn't sent the checked checkboxes. I have to recheck these before i receieve this selections. ( new selections are received immediately ).

Any idea why this happens?

jamie.nicholson
6 May 2009, 3:01 PM
Love the 'smart' CheckboxSelectionModel works a charm,

Just reading your usage and noticed the excel option is documented as false by default.
However in your code v1.7 it's set to true.

Cheers

serg555
14 May 2009, 12:54 PM
First of all very nice PI exactly what i needed.

However i have a small issue of which i haven't seen any questions in this thread yet, so i wonder why i do have this problem :)

When the grid 'loads' it nicely checks the checkboxes, however when i submit my form ( in this case ). It doesn't sent the checked checkboxes. I have to recheck these before i receieve this selections. ( new selections are received immediately ).

Any idea why this happens?
I also had the same, looks like only with this config everything works ok:

var sm = new Ext.grid.SmartCheckboxSelectionModel({
email: false,
excel:false,
alwaysSelectOnCheck:false
});

Also it uses Ext.state.CookieProvider() that can cause problems if you reload grid store with different data (it stops selecting initial rows if you click on some rows). I had to comment out all references to it in order to work properly.

renku
28 May 2009, 9:11 AM
When you are using SmartCheckBoxSelectionModel with multiple grids, then it can easily fail.

The main problem sits right at the beginning of the source code:



header: '<div id="x-grid3-hd-checker" class="x-grid3-hd-checker"> </div>',


An assumably unique ID is assigned to the header cell and then the checked/unchecked status of it is determined by looking up this cell by ID. But of course this will fail when you have more then one grid with SmartCheckBoxSelectionModel enabled.

Testcase:

Below is a code that demonstrates how it fails:



var MyGrid = Ext.extend(Ext.grid.GridPanel, {
initComponent: function() {
Ext.apply(this, {
store: new Ext.data.JsonStore({
url: 'objects/getList',
root: 'response',
fields: [
{name: 'checked', type: 'bool'},
{name: 'name'}
],
sortInfo: {field: 'name', direction: 'ASC'}
}),
sm: new Ext.grid.SmartCheckboxSelectionModel({
dataIndex: 'checked'
}),
columns: [
new Ext.grid.SmartCheckboxSelectionModel(),
{header: 'Name', dataIndex: 'name'}
],
frame: true,
width: 200,
autoHeight: true,
renderTo: document.body,
buttons: [
{
text: "Load",
handler: function() {
this.getStore().load();
},
scope: this
}
]
});

MyGrid.superclass.initComponent.call(this);
}
});

Ext.onReady(function(){
new MyGrid();
new MyGrid();
});


It creates two similar grids with a "Load" button.

When you check the header cell in first grid and load the second, then the items loaded to the second grid will have checkboxes checked. When you uncheck the box in first grid and reload the second, the checkboxes will be gone.

So the state of one grid affects the bahaviour of another. Not good at all.

Proposed fix:

Generate unique ID for the header <div> or use a class instead.

bt_bruno
15 Jun 2009, 10:40 AM
When you are using SmartCheckBoxSelectionModel with multiple grids, then it can easily fail.

The main problem sits right at the beginning of the source code:

header: '<div id="x-grid3-hd-checker" class="x-grid3-hd-checker"> </div>',
An assumably unique ID is assigned to the header cell and then the checked/unchecked status of it is determined by looking up this cell by ID. But of course this will fail when you have more then one grid with SmartCheckBoxSelectionModel enabled.

Testcase:

Below is a code that demonstrates how it fails:
...


Proposed fix:




constructor: function()
{
//define header
this.header = '<div id="'+ (this._headerID = Ext.id()) +'" class="x-grid3-hd-checker"> </div>';

//super
Ext.grid.SmartCheckboxSelectionModel.superclass.constructor.apply(this,arguments);
}



replace

var t = Ext.get('x-grid3-hd-checker');

for

var t = Ext.get(this._headerID);

ZaAaV
4 Dec 2009, 1:43 PM
Hey guys,

The checkboxes were correctly getting checked but the rows weren't highlighted automatically according to the dataIndex in my json response.

So I added defer to the part of the plugin where the row where set as selected in the initEvent (around line 164).

Here it is, hopefully this will help anyone else:



...
if((dataIndexValue == true || isSelected) && !Ext.state.Manager.loaded){
// This code will only run the first time a grid is loaded
// Make sure that any "checked" rows are also selected
if(!this.email || this.alwaysSelectOnCheck){this.grid.getSelectionModel().selectRow.defer(200,this,[i, true]);}
}
...


On another note, any chance you'd help me come up with a 'beforerowdeselect' function.
I want to add a Ext.MessageBox.confirm that would get displayed to gain user approval before effectively unchecking the checkbox but if I try doing that using the 'rowdeselect' event, the checkbox gets unchecked anyway (despite the user response...)

Any idea welcomed...

Thanks for the great plugin!

mysticav
17 Dec 2009, 12:59 AM
I've read that Ext 3.1 has made some improvements to CheckboxColumnModel

Does anybody knows if these changes will impact in this plugin ?

Have you tested on 3.1 ?

Thanks.

Greffin
17 Dec 2009, 1:17 AM
I've read that Ext 3.1 has made some improvements to CheckboxColumnModel

Does anybody knows if these changes will impact in this plugin ?

Have you tested on 3.1 ?

Thanks.

I've tested with 3.1, and found that this plugin will reverse the data from the store. I.e if the dataset contains the following:
{"CHECKED": "false"} the checkbox will be checked.
{"CHECKED": "true"} the checkbox will be unchecked.

This is because the CHECKED item is NOT a boolean, even though the Field is defined of type 'boolean'. I do not know if this is a bug in Ext or this plugin, but I've made the following changes which will provide the same funcionality as before on similar datasets (I wont post the entire plugin anew. Just my changes):

Insert before the initEvents function (Line 67):


parseBoolean : function(value){
if (Ext.isDefined(value) && Ext.isString(value)) {
return (value.toLowerCase() == 'true' ? true:false);
}
return value;
},
Replace the dataIndexValue in the on store load event handler (will be line 167):


var dataIndexValue = this.parseBoolean(p.data.items[i].data[dataIndex]); // the value of the dataIndex for each row
Replace the isChecked in the onMouseDown function (will be line 379):


var isChecked = this.parseBoolean(record.data[this.dataIndex]);
And the most important part, insert in the renderer function (will be line 443):


v = this.parseBoolean(v);
I hope this will save some headache for others.

Coen
6 Jan 2010, 4:47 AM
Since the update to 3.1 I've experienced a different issue with this model. Upon closing a tab window which contained a Grid with this model, FireBug reported to me the following error:


n is undefined in ext-all.js (line 7)

Or,


l is undefined in ext-all-debug.js (line 1537)

What I found out is that, when registering for the view's "columnmove" event in initEvent's grid render event handler, the handler is set to this.onColumnMove, which does not exist. I'm not sure if it has ever existed, but commenting out this line fixed the error and did not cause any side effects.

For me, this is line 87, but I've already made several different fixes (boolean render, header id) so it may differ to your line numbering.

kdeelstra
15 Feb 2010, 5:44 AM
Will this work in works in Ext js 3.1? Do you have live example?

NoahK17
15 Feb 2010, 8:00 AM
Will this work in works in Ext js 3.1? Do you have live example?

I honestly haven't touched this code since the summer of 2007. I've heard mixed reports about it working with 3.1, check back a few posts and see what people say. I also received a PM linking me to this post which talks about 3.1 compatibility with the SmartCheckboxSelectionModel: http://www.extjs.com/forum/showthread.php?t=88754 (may or may not be useful).

Long story short, when or if I find the need with my current job to code something that would require the SmartCheckboxSelectionModel, I will take the code and update it to work with 3.1 fully.

NoahK17
15 Feb 2010, 8:02 AM
Since the update to 3.1 I've experienced a different issue with this model. Upon closing a tab window which contained a Grid with this model, FireBug reported to me the following error:


n is undefined in ext-all.js (line 7)

Or,


l is undefined in ext-all-debug.js (line 1537)

What I found out is that, when registering for the view's "columnmove" event in initEvent's grid render event handler, the handler is set to this.onColumnMove, which does not exist. I'm not sure if it has ever existed, but commenting out this line fixed the error and did not cause any side effects.

For me, this is line 87, but I've already made several different fixes (boolean render, header id) so it may differ to your line numbering.
Coen, do you mind posting your full SmartCheckboxSelectionModel code changes here so I can update the original thread with a working 3.1 version?

Coen
15 Feb 2010, 12:46 PM
Sure, no problem!

I must add however that my use of your SmartCheckboxSelectionModel is limited to usage with email = true only and I have detached it from working with the StateManager - I use my own. Therefor I cannot guarantee it's perfectly compatible with 3.1.

Unfortunately the project I work with is not public so I do not have a live version for you to try, I'm sorry.

Usage:


var checkboxModel = new Ext.grid.SmartCheckboxSelectionModel({
dataIndex: 'Selected',
email: true
});

var grid = new Ext.grid.EditorGridPanel({
selModel: checkboxModel,
columns: [
checkboxModel,
...
],
...
});
Code:


/**
* @class Ext.grid.SmartCheckboxSelectionModel
* @extends Ext.grid.RowSelectionModel
*
* A custom selection model that renders a column of checkboxes that can be toggled to select or deselect rows.
* By passing in a dataIndex and a store, it can pre-check (and select) rows after it renders.
* Included are all the standard navigation options of a RowSelectionModel, including Up/Down arrow keyMaps and Ctrl/Shift selections.
*
* @param (object) config The configuration options, as highlighted below
* @param (string) dataIndex The field that contains the boolen true/false value for checked/selected rows
*
* @copyright June 4, 2008 <last updated: July 1, 2008>
* @author Noah Kronemeyer <nkronemeyer@therubicongroup.com>
* @version 1.7
*/
Ext.grid.SmartCheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {
constructor: function(){
this.header = '<div id="'+ (this.headerId = Ext.id()) +'" class="x-grid3-hd-checker"> </div>';
Ext.grid.SmartCheckboxSelectionModel.superclass.constructor.apply(this,arguments);
},
/**
* @header (string) Any valid text or HTML fragment to display in the header cell for the checkbox column
* (defaults to '<div id="x-grid3-hd-checker" class="x-grid3-hd-checker"> </div>'). The default CSS
* class of 'x-grid3-hd-checker' displays a checkbox in the header and provides support
* for automatic check all/none behavior on header click. This string can be replaced by
* any valid HTML fragment, but if you use a simple text string (e.g., 'Select Rows'), you must include it
* in the following format: <div id="x-grid3-hd-checker">&nbsp;Simple String</div>, in addition
* the automatic check all/none behavior will only work if the 'x-grid3-hd-checker' class is supplied.
*/
//header: '<div id="'+this.headerId+'" class="x-grid3-hd-checker"> </div>',
/**
* @width (int) The default width in pixels of the checkbox column (defaults to 20).
*/
width: 20,
/**
* @sortable (bool) Set to true if you want the checkbox column to be sortable.
*/
sortable: false,
/**
* @email (bool) Will mimic email client functionality by separating out the selection of rows
* with the checking of rows, similar to how Yahoo! or Gmail works. One could then
* apply different actions on checked rows vs. selected rows.
* Defaults to false.
*/
email: false,
/**
* @excel (bool) Mimics excel functionality when clicking on rows or checkboxes. If set to true,
* all other rows will be deselected and unchecked except the row you most recently
* clicked. If set to false, all previous selections will remain selected and/or checked
* as you click around the grid (as if you were holding down CTRL and clicking).
* Defaults to false.
*/
excel: true,

toggleSelect: true,

/**
* @alwaysSelectOnCheck
* (bool) If set to true, clicking a checkbox will always select the row, working in conjunction
* with the email option.
* Defaults to false.
*
*/
alwaysSelectOnCheck: false,

// private
menuDisabled: true,
fixed: true,
id: 'checker',
dataIndex: '', // Define the dataIndex when you construct the selectionModel, not here

// private
parseBoolean : function(value){
if (Ext.isDefined(value) && Ext.isString(value)) {
return (value.toLowerCase() == 'true' ? true:false);
}
return value;
},

// private
initEvents: function() {
// Call the parent
Ext.grid.SmartCheckboxSelectionModel.superclass.initEvents.call(this);
// Assign the handlers for the mousedown events
this.grid.on('render', function() {
var view = this.grid.getView();
//view.on('columnmove', this.onColumnMove, this);
view.mainBody.on('mousedown', this.onMouseDown, this);
Ext.fly(view.innerHd).on('mousedown', this.onHdMouseDown, this);
}, this);
// Disable the rowNav created in our parent object, otherwise pressing DOWN will go down two rows!
this.rowNav.disable();
// Create our new rowNav that controls checkboxes as well
this.rowNav2 = new Ext.KeyNav(this.grid.getGridEl(), {
"up": function(e) {
if (!e.shiftKey) {
if (!this.email) { this.selectPreviousChecked(e.shiftKey); }
if (this.email) { this.selectPrevious(e.shiftKey); }
}
else if (this.last !== false && this.lastActive !== false) {
var last = this.last;
if (!this.email) { this.selectRangeChecked(this.last, this.lastActive - 1); }
if (this.email) { this.selectRange(this.last, this.lastActive - 1); }
this.grid.getView().focusRow(this.lastActive);
if (last !== false) {
this.last = last;
}
}
else {
this.selectFirstRow();
if (!this.email) { this.toggleChecked(0, true); }
}
},
"down": function(e) {
if (!e.shiftKey) {
if (!this.email) { this.selectNextChecked(e.shiftKey); }
if (this.email) { this.selectNext(e.shiftKey); }
}
else if (this.last !== false && this.lastActive !== false) {
var last = this.last;
if (!this.email) { this.selectRangeChecked(this.last, this.lastActive + 1); }
if (this.email) { this.selectRange(this.last, this.lastActive + 1); }
this.grid.getView().focusRow(this.lastActive, true);
if (last !== false) {
this.last = last;
}
}
else {
this.selectFirstRow();
if (!this.email) { this.toggleChecked(0, true); }
}
},
scope: this
});
// Listen for the movement of the columns
this.grid.on('columnmove', function(p) {
var t = Ext.get(this.headerId);
if (t != null) {
if (t.dom.className != 'x-grid3-hd-checker') {
Ext.fly(t.dom.parentNode).removeClass('x-grid3-hd-checker');
}
}
});
// If we sent a store to the selModel, auto-select rows based on dataIndex
if (this.grid.store) {
this.grid.store.on('load', function(p) {
// This block of code checks the status of the checkbox header,
// and if checked, will check all other checkboxes (but not on the initial load)
var t = Ext.get(this.headerId);
if (t != null) {
if (t.dom.className == 'x-grid3-hd-checker' && Ext.state.Manager.loaded) {
var hd = Ext.fly(t.dom.parentNode);
var isChecked = hd.hasClass('x-grid3-hd-checker-on');
if (isChecked) {
hd.addClass('x-grid3-hd-checker-on');
if (!this.email) { this.selectAll(); }
this.selectAllChecked(true);
}
}
else {
Ext.fly(t.dom.parentNode).removeClass('x-grid3-hd-checker');
}
}

// This block of code will pre-select checkboxes based on the dataIndex supplied,
// but only on the initial load.
var dataIndex = this.grid.getSelectionModel().dataIndex; // the dataIndex for the selectionModel
if(this.grid.store == null) return;
var count = this.grid.store.getCount();
for (var i = 0, len = count; i < len; i++) {
var dataIndexValue = this.parseBoolean(p.data.items[i].data[dataIndex]); // the value of the dataIndex for each row
var isSelected = this.isSelected(i);
if ((dataIndexValue == true || isSelected) && !Ext.state.Manager.loaded) {
// This code will only run the first time a grid is loaded
// Make sure that any "checked" rows are also selected
if (!this.email || this.alwaysSelectOnCheck) { this.grid.getSelectionModel().selectRow(i, true); }
}
else if (isSelected) {
// Let the state.Manager check the correct rows now
if (!this.email) { this.toggleChecked(i, true); }
}
else {
// Uncheck everything else
if (!this.email) { this.toggleChecked(i, false); }
}
}
}, this);
}
},

/**
* private function that controls the checkboxes
*
* @param (int) rowIndex the row you want to toggle
* @param (bool) c optional flag set to either true (to check) or false (to uncheck)
* if no second param, the checkbox will toggle itself
*/
toggleChecked: function(rowIndex, c) {
if (this.locked) return;
var record = this.grid.store.getAt(rowIndex);
if (c === true) {
// Check
record.set(this.dataIndex, true);
}
else if (c === false) {
// Uncheck
record.set(this.dataIndex, false);
}
else {
// Toggle checked / unchecked
record.set(this.dataIndex, !record.data[this.dataIndex]);
}
this.fireEvent("rowcheckchanged", this, rowIndex, c, record);
},

/**
* private functions that toggles all checkboxes on or off depending on param
*
* @param (bool) c true to check all checkboxes, false to uncheck all checkboxes
* @param (int) e (optional) if an exception is given, all rows will be checked/unchecked except this row
*/
selectAllChecked: function(c, e) {
if (this.locked) return;
var count = this.grid.store.getCount();
for (var i = 0, len = count; i < len; i++) {
if (c) {
if (i !== e) {
this.toggleChecked(i, true);
}
}
else {
if (i !== e) {
this.toggleChecked(i, false);
}
}
}
},

/**
* private function that clears all checkboxes
* specifically used to deal with shift+arrow keys,
* but can also be called with fast param to quickly uncheck everything
*
* @param (bool) fast true to quickly deselect everything with no exceptions
*/
clearChecked: function(fast) {
if (this.locked) return;
if (fast !== true) {
var count = this.grid.store.getCount();
for (var i = 0, len = count; i < len; i++) {
var isSelected = this.isSelected(i);
if (!isSelected) {
this.toggleChecked(i, false);
}
}
}
else {
// Quick and dirty method to uncheck everything
this.selectAllChecked(false);
}
this.last = false;
},

/**
* private function used in conjuction with the shift key for checking multiple rows at once
*/
selectRangeChecked: function(startRow, endRow, keepExisting) {
if (this.locked) return;
if (!keepExisting) {
if (!this.email || this.alwaysSelectOnCheck) { this.clearSelections(); }
this.clearChecked();
}
if (startRow <= endRow) {
for (var i = startRow; i <= endRow; i++) {
if (this.grid.store.getAt(i)) {
this.toggleChecked(i, true);
if (!this.email || this.alwaysSelectOnCheck) { this.selectRow(i, true); }
}
}
}
else {
for (var i = startRow; i >= endRow; i--) {
if (this.grid.store.getAt(i)) {
this.toggleChecked(i, true);
if (!this.email || this.alwaysSelectOnCheck) { this.selectRow(i, true); }
}
}
}
},
/**
* private function that is used with the UP arrow keyMap
*/
selectPreviousChecked: function(keepExisting) {
if (this.hasPrevious()) {
// Select the next row
this.selectRow(this.last - 1, keepExisting);
// Set the focus
this.grid.getView().focusRow(this.last);
if (!this.email) {
// Check the current (selected) row
this.toggleChecked(this.last, true);
// Uncheck all other rows
this.selectAllChecked(false, this.last);
}
return true;
}
return false;
},
/**
* private function that is used with the DOWN arrow keyMap
*/
selectNextChecked: function(keepExisting) {
if (this.hasNext()) {
// Select the next row
if (!this.email) { this.selectRow(this.last + 1, keepExisting); }
// Set the focus
this.grid.getView().focusRow(this.last);
if (!this.email) {
// Check the current (selected) row
this.toggleChecked(this.last, true);
// Uncheck all other rows
this.selectAllChecked(false, this.last);
}
return true;
}
return false;
},

/**
* private function that executes when you click on any row
* will keep other row selections active as you click around
*/
handleMouseDown: function(g, rowIndex, e) {
var t = e.getTarget('.ux-row-action-item');
if (!t) {
if (e.button !== 0 || this.isLocked()) {
return;
};
var view = this.grid.getView();
var record = this.grid.store.getAt(rowIndex);
if (e.shiftKey && this.last !== false) {
var last = this.last;
this.selectRange(last, rowIndex, e.ctrlKey);
if (!this.email) { this.selectRangeChecked(last, rowIndex, e.ctrlKey); }
this.last = last; // reset the last
view.focusRow(rowIndex);
} else {
var isChecked = record.data[this.dataIndex];
var isSelected = this.isSelected(rowIndex);

if (isSelected && this.toggleSelect) {
this.deselectRow(rowIndex);
if (!this.email) { this.toggleChecked(rowIndex, false); }
} else {
if (!this.excel) {
this.selectRow(rowIndex, true);
if (!this.email) {
this.toggleChecked(rowIndex, true);
}
}
else {
this.selectRow(rowIndex, e.ctrlKey);
if (!this.email) {
this.selectRangeChecked(rowIndex, rowIndex, e.ctrlKey);
}
}
view.focusRow(rowIndex);
}
}
}
},
/**
* private function restricted to execute when you click a checkbox itself
*/
onMouseDown: function(e, t) {
if (t.className && t.className.indexOf('x-grid3-cc-' + this.id) != -1) {
e.stopEvent();
// Define variables
var view = this.grid.getView();
var rowIndex = view.findRowIndex(t);
var record = this.grid.store.getAt(rowIndex);
var isSelected = this.isSelected(rowIndex);
var isChecked = this.parseBoolean(record.data[this.dataIndex]);
// Logic to select/de-select rows and the checkboxes
if (!this.email || this.alwaysSelectOnCheck) {
if (isSelected) {
if (!isChecked && this.alwaysSelectOnCheck) {
this.toggleChecked(rowIndex, true);
}
else {
this.deselectRow(rowIndex);
this.toggleChecked(rowIndex, false);
}
}
else {
this.selectRow(rowIndex, true);
this.toggleChecked(rowIndex, true);
view.focusRow(rowIndex);
}
}
else {
if (isChecked) {
this.toggleChecked(rowIndex, false);
}
else {
this.toggleChecked(rowIndex, true);
}
}
view.focusRow(rowIndex);
}
// Load the state manager
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
Ext.state.Manager.loaded = true;
},


/**
* private function that executes when you click the checkbox header
*/
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');
if (!this.email || this.alwaysSelectOnCheck) { this.clearSelections(); }
this.clearChecked(true); // the true param enables fast mode
} else {
hd.addClass('x-grid3-hd-checker-on');
if (!this.email || this.alwaysSelectOnCheck) { this.selectAll(); }
this.selectAllChecked(true);
}
}
// Load the state manager
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
Ext.state.Manager.loaded = true;
},

/**
* private function that renders the proper checkbox based on your dataIndex variable
*
* @param (varchar) v the dataIndex passed into the selectionModel that contains whether a row is checked by default or not
*/
renderer: function(v, p, record) {
v = this.parseBoolean(v);
p.css += ' x-grid3-check-col-td';
return '<div class="x-grid3-check-col' + (v ? '-on' : '') + ' x-grid3-cc-' + this.id + '"> </div>';
}
});


Credits also to earlier posters in this thread!

mcouillard
16 Feb 2010, 2:08 PM
Working fine here on 3.1.1 without any changes to your plugin required. Thanks again!

(usage: just a simple non-paged grid of checkboxes down the left)

NoahK17
16 Feb 2010, 2:31 PM
Working fine here on 3.1.1 without any changes to your plugin required. Thanks again!

(usage: just a simple non-paged grid of checkboxes down the left)Oh, well that's great news. Thanks MC!

alien3d
26 Feb 2010, 2:29 AM
working fine in extjs 3.11 great more better then checkColumn.~o)

steffenk
3 Mar 2010, 4:51 AM
Thanks for this excellent extension. I use it with 3.1.1 and it works fine. Reading selected from store is one of the biggest highlight of this extension. You made my day!

alien3d
29 Mar 2010, 7:45 PM
There was a bug after reloading the store.The checkbox wouldn't tick.I check my json code and the output was the same.My temp solution was to not reload .

zribiuvt
19 Apr 2010, 8:35 AM
I adde "defer(200,this,[i, true])" but no difference, plz, can you help me to let selected by default checked rows

Hey guys,

The checkboxes were correctly getting checked but the rows weren't highlighted automatically according to the dataIndex in my json response.

So I added defer to the part of the plugin where the row where set as selected in the initEvent (around line 164).

Here it is, hopefully this will help anyone else:



...
if((dataIndexValue == true || isSelected) && !Ext.state.Manager.loaded){
// This code will only run the first time a grid is loaded
// Make sure that any "checked" rows are also selected
if(!this.email || this.alwaysSelectOnCheck){this.grid.getSelectionModel().selectRow.defer(200,this,[i, true]);}
}
...


On another note, any chance you'd help me come up with a 'beforerowdeselect' function.
I want to add a Ext.MessageBox.confirm that would get displayed to gain user approval before effectively unchecking the checkbox but if I try doing that using the 'rowdeselect' event, the checkbox gets unchecked anyway (despite the user response...)

Any idea welcomed...

Thanks for the great plugin!

zribiuvt
19 Apr 2010, 8:41 AM
I would like to know (v3.1) how to make rows checked by default, hightlighted? i read all messages of this forum and i tested all solution but no positive result. I am using Smart Checkbox Selection Model
Thanks to reply me as soon as possible

zribiuvt
20 Apr 2010, 2:42 AM
I have just changed
if((dataIndexValue == true || isSelected) && !Ext.state.Manager.loaded)
by
if((dataIndexValue == 'false' || isSelected)){

in the file SmartCheckColumn.js all works well!!

jbird526
18 May 2010, 6:22 AM
For anyone that is using the email:true setting to separate the checkbox and gridrow functionality I am using this hack to select only the checkboxes and pass their Ids in an ajax call. Its not great but it works for my needs.

Create a new renderer and assign a unique record Id as the div id

var cbsm = new Ext.grid.SmartCheckboxSelectionModel({
email: true,
renderer : function(v, p, record){
p.css += ' x-grid3-check-col-td';
return '<div id='+record.data.noteId+' class="x-grid3-check-col'+(v?'-on':'')+' x-grid3-cc-'+this.id+'"> </div>';
}

});

I then have a function that gets called by a button handler to return the Ids of only the checkboxes that are checked.


getChecked: function() {
var result = [];
var cb = this.getEl().query("div.x-grid3-check-col-on");
for (var i = 0; i < cb.length; i++) {
result.push(cb[i].id);
}
delete cb;
return result;
},

NoahK17
18 May 2010, 8:56 AM
Hey, thanks for that mod jbird! I'm glad people are still finding use out of this SelectionModel almost 2 years after I last worked on it. :)

Dipish
2 Jul 2010, 6:46 AM
Hey Noah thanks for the awesome plugin! I haven't tried it out yet but now I need it and going to use it, I used the Ext.ux.grid.CheckColumn plugin but it's too poor..

jbird526 your approach is interesting but I think that a more correct, data-aware way of doing this is filtering the data Store by the 'checked' field when collecting data from grid befora Ajax call, that's the way I do it. I also call suspendEvents() on the store so the grid records aren't really filtered out.

Chaoz
11 Oct 2010, 7:00 AM
I wonder if anyone can help here, I implemented this plugin and with 3.2.1 and I got it to work on first window create, after closing the window and reopening it, i would get and loading screen and an error in firebug

var count = this.grid.store.getCount();

thanks

Condor
11 Oct 2010, 7:12 AM
Closing a window will destroy everything inside, including the grid.

Either hide and reuse the window or close and completely recreate it.

abenomar
28 Jan 2011, 3:23 AM
Hello,

I have a probleme with my GridPanle when I try to sort checked rows , this is the scenario I do :
Check All Rows --> Sort by a name Column --> Deselect one row (checkbox) --> Sort again using date Column.
as result I have the grid with a lot of row unckecked., I don't know why.

Please Help

jamie.nicholson
20 Feb 2011, 9:26 AM
I use Saki's state provider and this extension(great extenstion btw), they don't mash. Saki's state provider is an alternative to the cookie provider. SmartCheckBoxSelectionModel sets the provider to be cookies, stomping Saki's provider.

To resolve the issue I just removed the state provider settings (method onMouseDown, onHDMouseDown), not sure if you want to remove them ongoing, could be better just to check to see if a state provider is defined before setting it.

http://www.sencha.com/forum/showthread.php?24970-Buffering-Http-State-Provider&p=573076

Thanks

NoahK17
23 Mar 2011, 6:27 AM
Hey Jamie, I saw your post in Saki's thread. I plan on going through all of these recent posts and modify the OP with any bug fixes or conflict changes with other mods. Thanks for your input!

NoahK17
23 Mar 2011, 10:22 AM
The mod has been updated to version 1.8 and includes the following features:

- new events, "checked" and "beforerowdeselect", both user requested
- new config option, "useStateManager", set to true to use the Cookie StateManager by default, or false to use your own StateManager
- compatibility fix, the default Cookie StateManager no longer conflicts with Saki's Http StateManager
- bug fix, the header ID is now uniquely generated as to avoid conflicts with multiple grids rendered on the same page
- tested with ExtJS v.3.2.1; let me know if there are any issues!

PS. Would a mod mind updating the title of the thread to denote that v1.8 is available as of 2011-03-23? It seems I've lost the ability to update thread titles. Cheers!

karimchebani
31 Mar 2011, 7:02 AM
It can be usefull to have SingleSelect Working.

Tested on Ext 3.3 and works fine, but SingleSelect isn't used.

dkeegan
21 Mar 2012, 11:36 AM
Are there any plans to get this extension working in Ext4? I tried it in 4.0.7 just to see if it would work and it didn't.


Uncaught Ext.Error: Attempting to extend from a class which has not been loaded on the page.

It looks like it's failing to extend Ext.grid.RowSelectionModel which I'm guessing doesn't exists in Ext4.

NoahK17
21 Mar 2012, 12:01 PM
Are there any plans to get this extension working in Ext4? I tried it in 4.0.7 just to see if it would work and it didn't.


Uncaught Ext.Error: Attempting to extend from a class which has not been loaded on the page.

It looks like it's failing to extend Ext.grid.RowSelectionModel which I'm guessing doesn't exists in Ext4.

Hi dkeegan,

This is completely untested, but...



REPLACE:
Ext.grid.SmartCheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {

WITH:
Ext.define('Ext.grid.SmartCheckboxSelectionModel', {
extend: 'Ext.selection.RowModel',


Ext4 uses a different way to define and extend classes if you aren't using the compatibility file. Oh, and Ext.grid.RowSelectionModel got renamed to Ext.selection.RowModel, so perhaps you'll only need to replace that single word in order for it to work in Ext4. Let me know if it works?

dkeegan
21 Mar 2012, 2:23 PM
NoahK17,

Thanks that got rid of that error. I'm not sure if I'm using the extension correctly this is the test code I've but together:



Ext.create('Ext.data.Store', {
storeId: 'SmartCheckboxSelectionStore',
fields: ['checked', 'location', 'product', 'car'],
data: {
'items': [
{
"checked": true,
"id": "1",
"location": "Atlanta",
"product": "Retail",
"car": "Luxury"
}, {
"checked": false,
"id": "2",
"location": "Atlanta",
"product": "Retail",
"car": "SUV"
}
]
},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
}
});
listPanel = Ext.create('Ext.grid.Panel', {
title: 'SmartCheckboxSelection',
store: Ext.data.StoreManager.lookup('SmartCheckboxSelectionStore'),
columns: [
{
header: 'Checked',
dataIndex: 'checked'
}, {
header: 'Location',
dataIndex: 'location',
flex: 1
}, {
header: 'Product',
dataIndex: 'product'
}, {
header: 'Car',
dataIndex: 'car'
}
],
selType: new Ext.grid.SmartCheckboxSelectionModel({
dataIndex: 'checked',
email: true
})
});


Is SmartCheckboxSelectionModel the selType? I am getting this error now:


Uncaught Ext.Error: Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. Missing required class: selection.[object Object]