-
13 Dec 2011 5:56 AM #21
Validation in ExtJS 4
Validation in ExtJS 4
We have not converted over to ExtJS 4 yet, so I can't help much, but after looking at the new grid code for version 4, it looks as though Ext.editor has just moved to Ext.grid.CellEditor. You might be able to override that with similar code to get it working. Sorry, just haven't gotten their yet, but I will re-post when we do.
allenlako
-
13 Dec 2011 1:28 PM #22
No worries - just wondering if anyone had figured it out yet.
I've managed to get it working in Ext 4 based off your changes for version 3. My code can probably can be improved though
Same changes to completeEdit as you, and just a minor change to onEditComplete. Not sure why but firing the 'edit' event (commented out in my code) clears out the x-form-invalid-field class.Code:Ext.override(Ext.Editor, { completeEdit : function(remainVisible) { var me = this, field = me.field, value; if (!me.editing) { return; } if (field.assertValue) { field.assertValue(); } value = me.getValue(); if (!field.isValid()) { if (me.revertInvalid !== false) { //me.cancelEdit(remainVisible); } //return; } if (String(value) === String(me.startValue) && me.ignoreNoChange) { me.hideEdit(remainVisible); return; } if (me.fireEvent('beforecomplete', me, value, me.startValue) !== false) { value = me.getValue(); if (me.updateEl && me.boundEl) { me.boundEl.update(value); } me.hideEdit(remainVisible); me.fireEvent('complete', me, value, me.startValue); } } }); // override to highlight invalid grid rows Ext.override(Ext.grid.plugin.CellEditing, { onEditComplete : function(ed, value, startValue) { var me = this, grid = me.grid, sm = grid.getSelectionModel(), activeColumn = me.getActiveColumn(), dataIndex; if (activeColumn) { dataIndex = activeColumn.dataIndex; me.setActiveEditor(null); me.setActiveColumn(null); me.setActiveRecord(null); delete sm.wasEditing; if (!me.validateEdit()) { return; } if (value !== startValue) { me.context.record.set(dataIndex, value); } else { grid.getView().getEl(activeColumn).focus(); } me.context.value = value; me.fireEvent('edit', me, me.context); // highlight invalid rows if (!ed.field.isValid(true)) { var cell = me.view.getCellByPosition(sm.position); cell = Ext.get(cell); cell.addCls('x-form-invalid-field'); } } } });
EDIT: Figured out why the edit event was causing the class to go away - I had a listener on edit which was updating another field of the record. This update caused the row to render again, and caused the x-form-invalid-field class to be removed. So unless you update the record, the updated code above should work.
Anyways, that is a basic working example for anyone who needs it.
-
1 Feb 2012 2:25 PM #23
-
1 Feb 2012 4:50 PM #24
I came up with the following version that is reusable as plugin. However, I still haven't figured out how to display the error message as qtip in Ext4. Also, how do I replace the "Ext.form.field.Text.prototype" call with a more generic code since the editor's field is not always a textfield, it can be numberfield. Please see lines in red color below. Any advice is greatly appreciated.
Test caseCode:Ext.define("bc.widgets.grid.plugin.KeepInvalidInputCellEditing",{ extend: "Ext.grid.plugin.CellEditing", alias: 'plugin.keepInvalidInputCellEditing', constructor: function(config) { this.callParent(arguments); this.on("beforestartedit", function(e, eOpts){ if (!e.record._valid) { e.record._valid = []; } e.field.record = e.record; e.field.col = e.col; }); }, /** * Override to highlight invalid grid rows. * @param ed * @param value * @param startValue */ onEditComplete : function(ed, value, startValue) { var me = this, grid = me.grid, sm = grid.getSelectionModel(), activeColumn = me.getActiveColumn(), dataIndex; if (activeColumn) { dataIndex = activeColumn.dataIndex; me.setActiveEditor(null); me.setActiveColumn(null); me.setActiveRecord(null); delete sm.wasEditing; if (!me.validateEdit()) { return; } // Only update the record if the new value is different than the // startValue, when the view refreshes its el will gain focus if (value !== startValue) { me.context.record.set(dataIndex, value); } else { grid.getView().getEl(activeColumn).focus(); } me.context.value = value; me.fireEvent('edit', me, me.context); //NOTE: hnguyen highlight invalid rows if (!ed.field.isValid(true)) { //var cell = me.view.getCellByPosition(sm.position); var record = me.context.record; var cell = me.getCell(record, activeColumn); cell = Ext.get(cell); cell.addCls('x-form-invalid-field'); //cell.addCls('x-grid-cell-invalid'); /* //record.errors is always undefined in Ext4. var errors = record.errors ? record.errors[dataIndex] : null; cell.attr = 'data-qtip="' + Ext.util.Format.htmlEncode(errors.join('<br />')) + '" data-qclass="x-tip x-form-invalid-tip"';*/ } } }, getEditor: function(record, column) { var me = this, editors = me.editors, editorId = column.getItemId(), editor = editors.getByKey(editorId); if (editor) { return editor; } else { editor = column.getEditor(record); if (!editor) { return false; } // Allow them to specify a CellEditor in the Column if (!(editor instanceof Ext.grid.CellEditor)) { editor = Ext.create('Ext.grid.CellEditor', { editorId: editorId, field: editor }); } editor.parentEl = me.grid.getEditorParent(); // editor.parentEl should be set here. editor.on({ scope: me, specialkey: me.onSpecialKey, complete: me.onEditComplete, canceledit: me.cancelEdit }); //NOTE: hnguyen Extra code to retain invalid input Ext.apply(editor, { completeEdit : function(remainVisible) { var me = this, field = me.field, value; if (!me.editing) { return; } // Assert combo values first if (field.assertValue) { field.assertValue(); } value = me.getValue(); //NOTE: hnguyen Check for allowInvalid configuration if(!field.allowInvalid && !field.isValid()){ if(me.revertInvalid !== false){ me.cancelEdit(remainVisible); } return; } if (String(value) === String(me.startValue) && me.ignoreNoChange) { me.hideEdit(remainVisible); return; } if (me.fireEvent('beforecomplete', me, value, me.startValue) !== false) { // Grab the value again, may have changed in beforecomplete value = me.getValue(); if (me.updateEl && me.boundEl) { me.boundEl.update(value); } me.hideEdit(remainVisible); me.fireEvent('complete', me, value, me.startValue); } } }); Ext.apply(editor.field, { validateValue: function(v) { //TODO: An editor's field is not always a textfield, it can be numberfield, etc...Need to fix this var valid = Ext.form.field.Text.prototype.validateValue.call(this, v); if (this.record){ this.record._valid[this.col] = valid; } return valid; } }); editors.add(editor); return editor; } } });
Code:Ext.define('TestNameItem', { extend: 'Ext.data.Model', fields: ["id", "name", "comment"] }); var myStore = Ext.create('Ext.data.Store', { model: 'TestNameItem', data: [{id: 1, name: 'ABC', comment: "First Text"}, {id: 2, name: "DEF", comment: "Second Text"}, {id: 3, name: "GHI", comment: "Third Text"}, {id: 4, name: "JKL", comment: "Fourth Text"} ] }); new Ext.container.Viewport({ renderTo: Ext.getBody(), layout: 'fit', items: [{ xtype: 'gridpanel', columnLines: true, plugins: [ Ext.create('bc.widgets.grid.plugin.KeepInvalidInputCellEditing', { //Ext.create('Ext.grid.plugin.CellEditing', { clicksToEdit: 1 }) ], selModel: new Ext.selection.RowModel(), store: myStore, columns: [{ text: "Name", dataIndex: "name", editor: { xtype: "textfield", allowBlank: false, maxLength: 3, allowInvalid: true } },{ text: "Comment", dataIndex: "comment", flex: 1 }]/*, listeners: { validateedit: function(e){ var errors = e.record.errors || {}; errors[e.field] = e.grid.lastActiveEditor.field.getErrors(); e.record.errors = errors; } }*/ }] });Last edited by vanessa_ng; 1 Feb 2012 at 4:53 PM. Reason: Need to add test case.
-
2 Feb 2012 1:20 PM #25
I solved the "record.errors is undefined" error, but I still haven't figured out a generic way to call validateValue function instead of using "Ext.form.field.Text.prototype" as in the red text below.
Code:Ext.define("bc.widgets.grid.plugin.KeepInvalidInputCellEditing",{ extend: "Ext.grid.plugin.CellEditing", alias: 'plugin.keepInvalidInputCellEditing', constructor: function(config) { this.callParent(arguments); this.on("beforestartedit", function(e, eOpts){ if (!e.record._valid) { e.record._valid = []; } e.field.record = e.record; e.field.col = e.col; }); //Added to solve record.errors is undefined error. this.on("validateedit", function(editor, e){ var errors = e.record.errors || {}; errors[e.field] = this.getEditor(e.record, e.column).field.getErrors(); e.record.errors = errors; }); }, /** * Override to highlight invalid grid rows. * @param ed * @param value * @param startValue */ onEditComplete : function(ed, value, startValue) { var me = this, grid = me.grid, sm = grid.getSelectionModel(), activeColumn = me.getActiveColumn(), dataIndex; if (activeColumn) { dataIndex = activeColumn.dataIndex; me.setActiveEditor(null); me.setActiveColumn(null); me.setActiveRecord(null); delete sm.wasEditing; if (!me.validateEdit()) { return; } // Only update the record if the new value is different than the // startValue, when the view refreshes its el will gain focus if (value !== startValue) { me.context.record.set(dataIndex, value); } else { grid.getView().getEl(activeColumn).focus(); } me.context.value = value; me.fireEvent('edit', me, me.context); //NOTE: hnguyen highlight invalid rows if (!ed.field.isValid(true)) { var record = me.context.record; var cell = me.getCell(record, activeColumn); cell = Ext.get(cell); cell.addCls('x-form-invalid-field'); //cell.addCls('x-grid3-cell-invalid'); var errors = record.errors ? record.errors[dataIndex] : null; var tip = Ext.create('Ext.tip.ToolTip', { target: cell, cls: "x-tip x-form-invalid-tip", html: Ext.util.Format.htmlEncode(errors.join('<br />')) }); } } }, getEditor: function(record, column) { var me = this, editors = me.editors, editorId = column.getItemId(), editor = editors.getByKey(editorId); if (editor) { return editor; } else { editor = column.getEditor(record); if (!editor) { return false; } // Allow them to specify a CellEditor in the Column if (!(editor instanceof Ext.grid.CellEditor)) { editor = Ext.create('Ext.grid.CellEditor', { editorId: editorId, field: editor }); } editor.parentEl = me.grid.getEditorParent(); // editor.parentEl should be set here. editor.on({ scope: me, specialkey: me.onSpecialKey, complete: me.onEditComplete, canceledit: me.cancelEdit }); //NOTE: hnguyen Extra code to retain invalid input Ext.apply(editor, { completeEdit : function(remainVisible) { var me = this, field = me.field, value; if (!me.editing) { return; } // Assert combo values first if (field.assertValue) { field.assertValue(); } value = me.getValue(); //NOTE: hnguyen Check for allowInvalid configuration if(!field.allowInvalid && !field.isValid()){ if(me.revertInvalid !== false){ me.cancelEdit(remainVisible); } return; } if (String(value) === String(me.startValue) && me.ignoreNoChange) { me.hideEdit(remainVisible); return; } if (me.fireEvent('beforecomplete', me, value, me.startValue) !== false) { // Grab the value again, may have changed in beforecomplete value = me.getValue(); if (me.updateEl && me.boundEl) { me.boundEl.update(value); } me.hideEdit(remainVisible); me.fireEvent('complete', me, value, me.startValue); } } }); Ext.apply(editor.field, { validateValue: function(v) { var valid = Ext.form.field.Text.prototype.validateValue.call(this, v); if (this.record){ this.record._valid[this.col] = valid; } return valid; } }); editors.add(editor); return editor; } } });
-
17 Sep 2012 7:19 AM #26
some operations, as sorting, filtering, synchronizes the store and other, doesn't restore cell cls added to the cell by means of cell.addCls function.



Reply With Quote