mjlecomte
7 Aug 2008, 6:16 PM
A fairly frequent question in the forums is how to disable editing in editor grids. Several options have been discussed, some of them are shown in #28 of the Grid FAQs.
I was thinking it might be more convenient to allow a custom function to be specified - a similar method is used with form validator (http://extjs.com/deploy/dev/docs/?class=Ext.form.TextField&method=validator) whereby the user can specify a custom function will be injected into the validation process.
Just thought I'd share my crude crack at it.
/**
* Ext grid ColumnModel Override
*
* @class Ext.grid.ColumnModel
* @extends Ext.util.Observable
*
*/
Ext.override(Ext.grid.ColumnModel, {
/**
* Returns true if the cell is editable. A custom function may be specified to enable or disable editing.
* @param {Number} colIndex The column index
* @param {Number} rowIndex The row index
* @param {Object} grid The grid
* @return {Boolean}
*/
isCellEditable : function(colIndex, rowIndex, grid){
// isCellEditable : function(colIndex, rowIndex){
/*change begin*/
if (typeof this.config[colIndex].enableEditor == "function") {
var field = this.getDataIndex(colIndex);
var selModel = grid.getSelectionModel();
var record = selModel.selection.record;
var cellValue = record.data[this.getDataIndex(colIndex)];
var result = this.config[colIndex].enableEditor(cellValue, colIndex, rowIndex, selModel, record, grid);
if (true !== result) {
//this.fireEvent('editDenied', this);
return false;
}
return true;
}
/*change end*/
return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
},
/*change begin*/
/*
* @cfg {Function} enableEditor A custom function that will be called before the editor is activated (defaults to null).
* If available, this function will be called and expected to return boolean true if the editor should be activated or false if the editor should be disabled.
* <p>The funtion will be called with the following parameters:
* <div class="mdetail-params"><ul>
* <li><b>cellValue</b> : String<p class="sub-desc">current field value</p></li>
* <li><b>colIndex</b> : Number<p class="sub-desc">The column index</p></li>
* <li><b>rowIndex</b> : Number<p class="sub-desc">The row index</p></li>
* <li><b>selModel</b> : Object<p class="sub-desc">The grid's selection model</p></li>
* <li><b>record</b> : Object<p class="sub-desc">Ext.data.Record[]</p></li>
* <li><b>grid</b> : Object<p class="sub-desc">The grid</p></li>
* </ul></div></p>
*/
enableEditor : null
/*change end*/
});
Ext.override(Ext.grid.EditorGridPanel, {
startEditing : function(row, col){
this.stopEditing();
/*change begin*/
// if(this.colModel.isCellEditable(col, row)){
if(this.colModel.isCellEditable(col, row, this)){
/*change end*/
this.view.ensureVisible(row, col, true);
var r = this.store.getAt(row);
var field = this.colModel.getDataIndex(col);
var e = {
grid: this,
record: r,
field: field,
value: r.data[field],
row: row,
column: col,
cancel:false
};
if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
this.editing = true;
var ed = this.colModel.getCellEditor(col, row);
if(!ed.rendered){
ed.render(this.view.getEditorParent(ed));
}
(function(){ // complex but required for focus issues in safari, ie and opera
ed.row = row;
ed.col = col;
ed.record = r;
ed.on("complete", this.onEditComplete, this, {single: true});
ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
this.activeEditor = ed;
var v = this.preEditValue(r, field);
ed.startEdit(this.view.getCell(row, col).firstChild, v);
}).defer(50, this);
}
}
}
});
Ext.override(Ext.grid.CellSelectionModel, {
/*change begin*/
//normalize selection models getSelected() method
getSelected: Ext.grid.CellSelectionModel.prototype.getSelectedCell,
/*change end*/
acceptsNav: function(row, col, cm){
/*change begin*/
//return !cm.isHidden(col) && cm.isCellEditable(col, row);
return !cm.isHidden(col) && cm.isCellEditable(col, row, this.grid);
/*change end*/
}
});
Note I think it would be nice if the selection model getSelected() method were normalized across the various selection models. That way if the selection model changes it doesn't cause errors, just returns different results.
Sample usage (replace column config shown in the edit-grid.js demo):
var cm = new Ext.grid.ColumnModel([{
...
},{
header: "Price",
dataIndex: 'price',
width: 70,
align: 'right',
renderer: 'usMoney',
editor: new fm.NumberField({
allowBlank: false,
allowNegative: false,
maxValue: 100000
}),
enableEditor: function(cellValue, colIndex, rowIndex, selModel, record, grid){
//'this' is the individual column's config object
return (cellValue<5) ? true : false;
}
},{
...
]);
Maybe could also have some defaultEnableEditor (similar to defaultSortable (http://extjs.com/deploy/dev/docs/?class=Ext.grid.ColumnModel&method=defaultSortable)) config so could specify on the grid in general.
I was thinking it might be more convenient to allow a custom function to be specified - a similar method is used with form validator (http://extjs.com/deploy/dev/docs/?class=Ext.form.TextField&method=validator) whereby the user can specify a custom function will be injected into the validation process.
Just thought I'd share my crude crack at it.
/**
* Ext grid ColumnModel Override
*
* @class Ext.grid.ColumnModel
* @extends Ext.util.Observable
*
*/
Ext.override(Ext.grid.ColumnModel, {
/**
* Returns true if the cell is editable. A custom function may be specified to enable or disable editing.
* @param {Number} colIndex The column index
* @param {Number} rowIndex The row index
* @param {Object} grid The grid
* @return {Boolean}
*/
isCellEditable : function(colIndex, rowIndex, grid){
// isCellEditable : function(colIndex, rowIndex){
/*change begin*/
if (typeof this.config[colIndex].enableEditor == "function") {
var field = this.getDataIndex(colIndex);
var selModel = grid.getSelectionModel();
var record = selModel.selection.record;
var cellValue = record.data[this.getDataIndex(colIndex)];
var result = this.config[colIndex].enableEditor(cellValue, colIndex, rowIndex, selModel, record, grid);
if (true !== result) {
//this.fireEvent('editDenied', this);
return false;
}
return true;
}
/*change end*/
return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
},
/*change begin*/
/*
* @cfg {Function} enableEditor A custom function that will be called before the editor is activated (defaults to null).
* If available, this function will be called and expected to return boolean true if the editor should be activated or false if the editor should be disabled.
* <p>The funtion will be called with the following parameters:
* <div class="mdetail-params"><ul>
* <li><b>cellValue</b> : String<p class="sub-desc">current field value</p></li>
* <li><b>colIndex</b> : Number<p class="sub-desc">The column index</p></li>
* <li><b>rowIndex</b> : Number<p class="sub-desc">The row index</p></li>
* <li><b>selModel</b> : Object<p class="sub-desc">The grid's selection model</p></li>
* <li><b>record</b> : Object<p class="sub-desc">Ext.data.Record[]</p></li>
* <li><b>grid</b> : Object<p class="sub-desc">The grid</p></li>
* </ul></div></p>
*/
enableEditor : null
/*change end*/
});
Ext.override(Ext.grid.EditorGridPanel, {
startEditing : function(row, col){
this.stopEditing();
/*change begin*/
// if(this.colModel.isCellEditable(col, row)){
if(this.colModel.isCellEditable(col, row, this)){
/*change end*/
this.view.ensureVisible(row, col, true);
var r = this.store.getAt(row);
var field = this.colModel.getDataIndex(col);
var e = {
grid: this,
record: r,
field: field,
value: r.data[field],
row: row,
column: col,
cancel:false
};
if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
this.editing = true;
var ed = this.colModel.getCellEditor(col, row);
if(!ed.rendered){
ed.render(this.view.getEditorParent(ed));
}
(function(){ // complex but required for focus issues in safari, ie and opera
ed.row = row;
ed.col = col;
ed.record = r;
ed.on("complete", this.onEditComplete, this, {single: true});
ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
this.activeEditor = ed;
var v = this.preEditValue(r, field);
ed.startEdit(this.view.getCell(row, col).firstChild, v);
}).defer(50, this);
}
}
}
});
Ext.override(Ext.grid.CellSelectionModel, {
/*change begin*/
//normalize selection models getSelected() method
getSelected: Ext.grid.CellSelectionModel.prototype.getSelectedCell,
/*change end*/
acceptsNav: function(row, col, cm){
/*change begin*/
//return !cm.isHidden(col) && cm.isCellEditable(col, row);
return !cm.isHidden(col) && cm.isCellEditable(col, row, this.grid);
/*change end*/
}
});
Note I think it would be nice if the selection model getSelected() method were normalized across the various selection models. That way if the selection model changes it doesn't cause errors, just returns different results.
Sample usage (replace column config shown in the edit-grid.js demo):
var cm = new Ext.grid.ColumnModel([{
...
},{
header: "Price",
dataIndex: 'price',
width: 70,
align: 'right',
renderer: 'usMoney',
editor: new fm.NumberField({
allowBlank: false,
allowNegative: false,
maxValue: 100000
}),
enableEditor: function(cellValue, colIndex, rowIndex, selModel, record, grid){
//'this' is the individual column's config object
return (cellValue<5) ? true : false;
}
},{
...
]);
Maybe could also have some defaultEnableEditor (similar to defaultSortable (http://extjs.com/deploy/dev/docs/?class=Ext.grid.ColumnModel&method=defaultSortable)) config so could specify on the grid in general.