PDA

View Full Version : EditableGrid - Shows editors for all cells



Condor
1 Sep 2009, 5:09 AM
EditorGridPanel only supports one editor for each column and the editor is only shown after single or double clicking the cell.
EditorGridPanel is not designed to show editors on every cell, because this would make the browser extremely slow with large datasets.

I created this plugin to show editors for all cells in a GridPanel (so not an EditorGridPanel!).

As noted above: Do NOT use this plugin for large datasets!

The plugin:

Ext.ns('Ext.ux.grid');
Ext.ux.grid.EditableGrid = Ext.extend(Object, {
init : function(grid){
Ext.apply(grid.getView(), {
editors: [],
editorPadding: 2,
renderUI : function(){
this.constructor.prototype.renderUI.call(this);
this.el.addClass('x-grid-editing');
},
updateAllColumnWidths : function(){
this.constructor.prototype.updateAllColumnWidths.call(this);
var editors = this.editors,
rows = editors.length,
cols = this.cm.getColumnCount(),
col, row, ed, w = [];
for(col = 0; col < cols; col++){
w[col] = this.cm.getColumnWidth(col) - this.editorPadding;
}
for(row = 0; row < rows; row++){
for(col = 0; col < cols; col++){
ed = editors[row][col];
if(ed){
ed.setWidth(w[col]);
}
}
}
},
updateColumnWidth : function(col, width){
this.constructor.prototype.updateColumnWidth.call(this, col, width);
var editors = this.editors,
rows = editors.length,
row, ed,
w = this.cm.getColumnWidth(col) - this.editorPadding;
for(row = 0; row < rows; row++){
ed = editors[row][col];
if(ed){
ed.setWidth(w);
}
}
},
afterRender : function(){
this.constructor.prototype.afterRender.call(this);
this.destroyAllEditors();
this.renderEditors(0, this.ds.getCount() - 1);
},
insertRows : function(dm, firstRow, lastRow, isUpdate){
this.constructor.prototype.insertRows.call(this, dm, firstRow, lastRow, isUpdate);
var last = dm.getCount() - 1;
if(!isUpdate && firstRow === 0 && lastRow >= last){
return;
}
this.renderEditors(firstRow, lastRow);
},
deleteRows : function(dm, firstRow, lastRow){
if(dm.getRowCount() >= 1){
this.destroyEditors(firstRow, lastRow);
}
this.constructor.prototype.deleteRows.call(this, dm, firstRow, lastRow);
},
refreshRow : function(record){
var ds = this.ds, index;
if(typeof record == 'number'){
index = record;
record = ds.getAt(index);
if(!record){
return;
}
}else{
index = ds.indexOf(record);
if(index < 0){
return;
}
}
this.destroyEditors(index, index);
this.constructor.prototype.refreshRow.call(this, record);
this.renderEditors(index, index);
},
refresh : function(headersToo){
this.destroyAllEditors();
this.constructor.prototype.refresh.call(this, headersToo);
this.renderEditors(0, this.ds.getCount() - 1);
},
destroy : function(){
this.destroyAllEditors();
this.constructor.prototype.destroy.call(this);
},
focusCell : function(row, col, hscroll){
this.syncFocusEl(this.ensureVisible(row, col, hscroll));
var ed = this.editors[row][col], focusEl = ed ? ed : this.focusEl;
if(Ext.isGecko){
focusEl.focus();
}else{
focusEl.focus.defer(1, this.focusEl);
}
},
renderEditors: function(startRow, endRow){
var args = [startRow, 0],
cols = this.cm.getColumnCount(),
col, row, ed, w = [], rec, r, di, cell;
for(col = 0; col < cols; col++){
w[col] = this.cm.getColumnWidth(col) - this.editorPadding;
}
for(row = startRow; row <= endRow; row++){
r = [];
rec = this.ds.getAt(row);
for(col = 0; col < cols; col++){
ed = this.cm.isCellEditable(col, row) ? this.cm.getCellEditor(col, row) : null;
if(ed){
cell = this.getCell(row, col).firstChild;
cell.parentNode.removeAttribute('tabindex');
cell.innerHTML = '';
di = this.cm.getDataIndex(col);
ed = ed.field.cloneConfig({
value: rec.get(di),
width: w[col],
renderTo: cell,
ctCls: 'x-small-editor x-grid-editor ux-editable-grid'
});
ed.on('blur', this.onEditorBlur, {
store: this.ds,
row: row,
dataIndex: di
});
}
r.push(ed);
}
args.push(r);
}
this.editors.splice.apply(this.editors, args);
},
destroyEditors: function(startRow, endRow){
var removed = this.editors.splice(startRow, endRow - startRow + 1);
Ext.destroy(removed);
},
destroyAllEditors: function(){
Ext.destroy(this.editors);
this.editors = [];
},
onEditorBlur: function(field){
this.store.getAt(this.row).data[this.dataIndex] = field.getValue();
}
});
}
});
Ext.preg('editable-grid', Ext.ux.grid.EditableGrid);
which requires the following css rule:

.ux-editable-grid {
padding: 0;
}

Usage example:

Ext.onReady(function(){
Ext.QuickTips.init();
new Ext.grid.GridPanel({
title: 'EditableGrid plugin test',
width: 250,
height: 150,
store: [[1, 'One'], [2, 'Two'], [3, 'Three'], [4, 'Four'], [5, 'Five']],
viewConfig: {
forceFit: true
},
columns: [{
header: 'Value',
dataIndex: 'field1',
editor: {
xtype: 'numberfield',
minValue: 0,
maxValue: 100
}
},{
header: 'Text',
dataIndex: 'field2',
editor: {
xtype: 'textfield',
allowBlank: false
}
}],
plugins: [{
ptype: 'editable-grid'
}],
renderTo: Ext.getBody()
});
});

mystix
1 Sep 2009, 10:09 AM
there might still be a way to cheat and use 1 editor per column...

what if we style all the inputs to look like textfields, but move/show/hide the column editor the way the editorgridpanel does. would that help to reduce the overhead of per-cell component creation?

Condor
1 Sep 2009, 10:25 AM
A few problems with that solution:
1. You would have to create a specific renderer for every editor type so the cell looks like the editor. The list of renderer should be extendable to support form field extensions.
3. A mouse down on a cell would move the editor to that cell, but the mouse down event would not be forwarded to the field (which could mean that a second click is required to actually use the field).

tchitani
1 Sep 2009, 7:36 PM
Great plugin.

Can this plug-in be used to display editors not to ALL cells?

Condor
1 Sep 2009, 9:56 PM
Great plugin.

Can this plug-in be used to display editors not to ALL cells?

It won't display an editor if the column isn't editable (no editor or isCellEditable returns false).

canxss
2 Sep 2009, 2:16 PM
Hi Condor,

I accidentally saw this plugin while I was struggling to show slider in EditorGridPanel. Actually I was waiting your reply to this post (http://extjs.com/forum/showthread.php?p=381523#post381523), which was about the same problem. This is what I need and slider renders perfectly!

But I'm still gonna insist on using this plugin for EditorGridPanel :) I understand that using this kind of feature on EditorGridPanel with a large dataset will slow down the browser but as I said in the above mentioned post, the dataset that I'm gonna use will have 5-6 records at max. So I believe I won't have any performance problems. And since I only need one column (the one that will be using the slider as an editor) to show the slider at all times, I changed your renderEditors method in order to do rendering if there is an 'alwaysShowEditor' option with "true" value for the column config. So even though the column has an editor, editor won't be rendered unless the alwaysShowEditor === true, so this will also help performance.

Is there a possibility to have this plugin work also for EditorGridPanel?

Thanks in advance

canxss
2 Sep 2009, 3:21 PM
Hi Condor,

I tried to use the plugin for EditorGridPanel and made it work by using the previously mentioned "alwaysShowEditor"option. In my extended EditorGridPanel, I've overridden the startEditing prototype method and prevented it to work for columns that have alwaysShowEditor === true.

So far it's working without a problem but since I'm not that much into inner workings of Ext JS, I wanted to ask if this is enough.

Thanks

Condor
2 Sep 2009, 9:26 PM
Yes, that should do it.

ps. Does your slider control fire the required 'blur' event?

canxss
3 Sep 2009, 1:17 AM
No, I've only copied the necessary Ext.form.Field prototype methods to Ext.Slider in order to be able to use it as an editor in EditorGridPanel. And as much as I've seen it doesn't fire 'blur' event.

I've checked out your plugin and if I'm not wrong without the blur event the value on slider will not be written back to store? Am I correct?

Is it easy to add blur event to slider?

Thanks

Condor
3 Sep 2009, 3:17 AM
To be compatible with Ext.form.Field, you should attach a blur event handler to the focusEl element and fire a change and a blur event on the component.

canxss
3 Sep 2009, 11:49 AM
Hi Condor,

I tried to attach blur event although I don't think that it's totally OK. But I've had another problem while using SliderTip plugin for the sliders in the EditorGridPanel. The problem starts to appear after a second call goes to renderEditors method (for example, from refreshRow or refresh methods).

I've changed your example and used an EditorGridPanel and also put my extended Ext.ux.form.Slider field as editor to the first column. When you run the example, change the sliders and then hit 'Plugin Refresh' button, then again try to change one of the sliders and then you should see attached error.

Can you take a look at the problem?

And also in the refreshRow method of the plugin, renderEditors method is called after call to the GridView's refreshRow method. But gridView's refreshRow method calls the insertRow method which also calls renderEditors method. So during a call to refreshRow method renderEditors method is called twice and 'editor' array's count increases.

And I would like to ask one more thing: in renderEditors, what happens if the editor has plugins while ed.field.cloneConfig is called? They don't seem to be cloned or are they? Could the above problem be related to this?

Thanks in advance

vladsch
21 Nov 2009, 7:31 AM
Hi Condor,

Can you clarify about license of this plugin? Under what license I can use the plugin?
Thanks

Condor
21 Nov 2009, 11:27 AM
Hi Condor,

Can you clarify about license of this plugin? Under what license I can use the plugin?
Thanks

You can use it under the MIT Licence (http://en.wikipedia.org/wiki/MIT_License).

darklow
11 Oct 2010, 10:35 PM
Does anyone has some updates or fixes on this plugin?
There are some bugs, for example, by some reason you cannot select existing text (by mouse cursor) in textfield editor
Thanks.

Condor
11 Oct 2010, 11:25 PM
Do you have this problem on all browsers or just on Firefox? In Firefox it's a z-index issue. You CAN select text, but the selection isn't visible.

Try playing with the position style on the <input> or parent elements...

lynxua
27 Oct 2010, 2:42 AM
This plugin doesn't work with ext 3.3.0.

"this.el is undefined" error in "this.el.addClass('x-grid-editing');"

Condor
27 Oct 2010, 2:59 AM
This plugin doesn't work with ext 3.3.0.

"this.el is undefined" error in "this.el.addClass('x-grid-editing');"

Try replacing "renderUI" with "afterRenderUI".

lynxua
27 Oct 2010, 3:17 AM
Works now. Thank you.

brian_peterson
12 Jul 2011, 11:55 AM
We have been working with this plugin with ExtJS version 3.2.

With a text field we have to click the grid cell twice? Why is this?

This code appears to be the issue:


this.syncFocusEl(this.ensureVisible(row, col, hscroll));
var ed = this.editors[row][col], focusEl = ed ? ed : this.focusEl;

if(Ext.isGecko)
{
focusEl.focus();
}
else
{
focusEl.focus.defer(1, this.focusEl);
}


Which is from the focusCell, from the original plugin. We are using Windows XP with Internet Explorer 8.
We were able to fix the issue by just commenting out everything in the focusCell function... Why? What does this code try and do?

The second bug is if you edit cells and quickly tab, while editing another cell, some of the editable cells disappear from the screen (mostly at random). See attached image.

The disappearing text field is still puzzling us… Has anyone found a work-around for this?

Thanks!

dhanrajb4
21 Jan 2013, 3:31 AM
hi condor,

the plugin is great and meets my requirement.

but i have one problem like when i select a value for combo box after the editing is completed.

the afteredit event of my editorgridpanel is not called.

can u help me to solve this problem

can any body help me

srinivasp
25 Aug 2013, 9:58 PM
Hi,
This is great plug in..Can any one has the same plugin for ExtJs 4.2 ..Becoz the current one not working with 4.X..

Any help or suggestions appretiated..

Thanks in Advance..

jakejamessteele
16 Jan 2014, 12:44 PM
Was this ever ported to Extjs 4.2?