PDA

View Full Version : I want my selected grid rows to remain selected. Even if I'm editing a cell. But no..



JPKramer707
2 Nov 2012, 2:55 PM
So, I have a grid. I have a thousand rows selected, and it took me an hour to pick out the right ones. See below (only five rows pictured, obviously)

39785

Now, imagine I want to change that "asdf" to "asdfg" using the nifty cell editor. No problem! I'll just click it, and...
39786

$%*@... why did that happen? Where are my selections? It looks like Extjs is trying to be obnoxiously helpful.

How can I prevent a cell editor click from messing with my selections?

Yours Truly,
-Kramer

mitchellsimoens
5 Nov 2012, 6:46 AM
The reason is because when you are editing you click on the grid row causing the grid to select that row.

JPKramer707
5 Nov 2012, 10:30 AM
Thanks Mitchell. I figured as much. Is Extjs capable of ignoring such clicks when they are for the purpose of cell editing? Could Extjs keep row selection state unchanged for all actions except for clicking the checkbox column? That would be spectacular.

mitchellsimoens
5 Nov 2012, 10:43 AM
You would have to override the selection model and check if the mouse down was over a certain element.

The issue with selection vs editing is the selection is done in the mousedown event where edit is either in the click or dblclick event so the selection is always going to happen before the editor even knows what's going on.

JPKramer707
5 Nov 2012, 11:08 AM
Ah! Gracias, SeƱor Forum Manager! Buenos huevos.

JPKramer707
9 Nov 2012, 12:12 PM
After some time, I realized that your suggestion sounds a lot like the checkOnly (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.selection.CheckboxModel-cfg-checkOnly) option of Ext.selection.CheckboxModel. But I'm already using that option.

Also, when I change my clicksToEdit (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.grid.plugin.CellEditing-cfg-clicksToEdit) option on my Ext.grid.plugin.CellEditing plugin to "2", the first click has no effect on the selection of any rows in my grid.

Both of these clues lead me to believe that the selection model is not what is causing the problem here.

So, what is?

Well, with clicksToEdit (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.grid.plugin.CellEditing-cfg-clicksToEdit) set to "2", I double-click on a cell to edit it, and Bam! As the cell editor appears, all rows deselect, and the row I'm editing within selects.

So, I think it's Ext.grid.plugin.CellEditing that's causing this. I did some investigation.

Here is Ext.grid.plugin.CellEditing.startEdit()

startEdit: function(record, columnHeader) {
// ... snip ...
me.grid.view.cancelFocus();
me.view.focusCell({
row: context.rowIdx,
column: context.colIdx
});
ed = false;
if (ed) {
me.editTask.delay(15, me.showEditor, me, [ed, context, value]);
return true;
}
return false;
}

If I add the line above (in red) "ed = false;" then row selection remains unchanged, but the cell editor doesn't appear, which is still a problem.

Why is the cell editor messing with row selections? What can we do about this?

Thanks again,
-Kramer

JPKramer707
9 Nov 2012, 3:27 PM
In the absence of an official solution, I developed this extension to Ext.grid.plugin.CellEditing. It works pretty well.


Ext.define('Ext.grid.plugin.CellEditing', {
extend: 'Ext.grid.plugin.CellEditing',
toReselectAfterEdit: [],

showEditor: function(ed, context, value) {
var xsm = this.grid.getSelectionModel();
//if (typeof(this.toReselectAfterEdit) == 'undefined') this.toReselectAfterEdit = [];
if (xsm.isSelected(context.record)) this.toReselectAfterEdit.push(context.record);

var me = this,
record = context.record,
columnHeader = context.column,
sm = me.grid.getSelectionModel(),
selection = sm.getCurrentPosition();

me.context = context;
me.setActiveEditor(ed);
me.setActiveRecord(record);
me.setActiveColumn(columnHeader);

/*
if (sm.selectByPosition && (!selection || selection.column !== context.colIdx || selection.row !== context.rowIdx)) {
sm.selectByPosition({
row: context.rowIdx,
column: context.colIdx
});
}
*/

ed.startEdit(me.getCell(record, columnHeader), value);
me.editing = true;
me.scroll = me.view.el.getScroll();
},

completeEdit: function() {
this.callParent(arguments);
this.reselectRowsThatShouldNeverHaveBeenDeselected();
},

onEditComplete: function() {
this.callParent(arguments);
this.reselectRowsThatShouldNeverHaveBeenDeselected();
},

reselectRowsThatShouldNeverHaveBeenDeselected: function() {
if (this.toReselectAfterEdit) {
var record;
while (record = this.toReselectAfterEdit.pop()) {
this.grid.getSelectionModel().deselect(record);
this.grid.getSelectionModel().select(record, true);
}
}
}
});

m.k
10 Nov 2012, 11:42 AM
You should avoid using toReselectAfterEdit: [] in the Class definition, because this Array reference is shared between all instances of the Class through their prototype.
Try to always initialize reference type class members inside the constructor.

JPKramer707
12 Nov 2012, 9:57 AM
Thanks m.k, you're right. Cleaned up version is here:


Ext.define('Ext.grid.plugin.CellEditing', {
extend: 'Ext.grid.plugin.CellEditing',

constructor: function() {
this.callParent(arguments);
this.toReselectAfterEdit = [];
},

showEditor: function(ed, context, value) {
var me = this,
record = context.record,
columnHeader = context.column,
sm = me.grid.getSelectionModel(),
selection = sm.getCurrentPosition();

if (sm.isSelected(context.record)) this.toReselectAfterEdit.push(context.record);
me.context = context;
me.setActiveEditor(ed);
me.setActiveRecord(record);
me.setActiveColumn(columnHeader);

/*
// The absence of this piece of code from the parent method is key.
if (sm.selectByPosition && (!selection || selection.column !== context.colIdx || selection.row !== context.rowIdx)) {
sm.selectByPosition({
row: context.rowIdx,
column: context.colIdx
});
}
*/

ed.startEdit(me.getCell(record, columnHeader), value);
me.editing = true;
me.scroll = me.view.el.getScroll();
},

completeEdit: function() {
this.callParent(arguments);
this.reselectRowsThatShouldNeverHaveBeenDeselected();
},

onEditComplete: function() {
this.callParent(arguments);
this.reselectRowsThatShouldNeverHaveBeenDeselected();
},

reselectRowsThatShouldNeverHaveBeenDeselected: function() {
if (this.toReselectAfterEdit) {
var record;
while (record = this.toReselectAfterEdit.pop()) {
this.grid.getSelectionModel().deselect(record);
this.grid.getSelectionModel().select(record, true);
}
}
}
});