Reputation: 3081
Ext.define('Workshop.store.WorkType',
{
extend: 'Ext.data.Store',
model: 'Workshop.model.WorkType',
autoLoad: true,
autoSync: true,
pageSize: 25,
proxy:
{
type: 'ajax',
api:
{
read: '/ajax_js.php?func=WorkType::selectRow',
update: '/ajax_js.php?func=WorkType::updateRow',
create: '/ajax_js.php?func=WorkType::insertRow',
destroy: '/ajax_js.php?func=WorkType::deleteRow'
},
reader:
{
type: 'json',
root: 'root',
successProperty: 'success',
totalProperty: 'totalCount'
}
}
});
I have this store definition and I want to use it in a grid with editor plugin:
Ext.define('Ext.ux.EditorGrid',
{
extend: 'Ext.grid.Panel',
plugins:
[
Ext.create('Ext.grid.plugin.RowEditing',
{
clicksToEdit: 2
})
],
store: Ext.create('Workshop.store.WorkType'),
border: false,
columns:
[
{header: trans.translate('WORKTYPENAME'), dataIndex: 'name', flex: 1, editor: 'textfield'},
{header: trans.translate('FACTOR'), dataIndex: 'factor', flex: 1, editor: 'textfield'}
]
});
Everything works fine if I enter valid data, but what if server validation fails, how can I achieve that fields get marked and editor does not close?
This can also be used on a new record insertion too, how do I validate new data?
Upvotes: 2
Views: 3300
Reputation: 4117
here's a quick hack I made for a demo project:
below is the listeners hash for the rowedit plugin
listeners: {
canceledit: function(editor, e, options) {
if (e.record.phantom) {
return e.grid.store.remove(e.record);
}
},
edit: function(editor, e) {
var ed, grid;
ed = editor;
grid = editor.cmp;
grid.el.mask('Loading ...', 'x-loading');
return e.record.save({
success: function(record, operation) {
return grid.el.unmask();
},
failure: function(record, operation) {
grid.el.unmask();
ed.startEdit(grid.store.indexOf(record), 0);
return Ext.Object.each(operation.request.proxy.reader.jsonData.errors, function(field, errors) {
return ed.editor.down("[name=" + field + "]").markInvalid(errors);
});
}
});
}
}
the server should return a response like this:
{
success: false,
errors: {
field1: ['error message1'],
field2: ['error message2', 'error message3']
}
}
Upvotes: 2
Reputation: 16130
I have partial solution of your problem. I've created validate
method in proxy which validates data before saving. It wasn't easy, but eventually it works (at least partially). It's not very beautiful, but it's was really hard to make this work. This should be good entry point for creating validation on save. Code is below.
// extended RowEditor
Ext.define('Ext.grid.ExtRowEditor', {
extend: 'Ext.grid.RowEditor',
// here we can plugin into editor
onFieldAdd: function(map, fieldId, column) {
this.callParent(arguments);
var plugin = this.editingPlugin;
var editor = column.getEditor();
// if not yet initialized
if (editor._extRowEditorInit === undefined) {
// create interceptor to fire event that will eventually send validation request to the server
editor.validate = Ext.Function.createInterceptor(editor.validate, function() {
this.fireEvent('validationneeded', this, column, plugin);
}, editor);
// create validator
editor.validator = function() {
if (!this.errorValue) {
return true;
}
if (!this.getValue()) {
return true;
}
return (this.errorValue.toString() == this.getValue().toString()) ? this.errorMessage : true;
};
// create validationneeded event handler
editor.on('validationneeded', this.onValidationneeded, this, { buffer: 100 });
// mark initialized
editor._extRowEditorInit = true;
}
},
// send request to server
onValidationneeded: function(editor, column, plugin) {
var context = plugin.context;
var store = context.store;
var record = context.record;
// if nothing changed we don't need to send request
if (record.get(column.dataIndex) === editor.getValue()) {
return;
}
// copy record; at this point original record still has old value, so we must set this from editor
record = new record.store.model(record.data);
record.set(column.dataIndex, editor.getValue());
// create operation
var operation = Ext.create('Ext.data.Operation', {
action : 'validate',
records: [
record
]
});
var scope = { editor: editor, plugin: plugin };
// create handler on exception; there is no way to access exception data from regular doRequest handler
store.proxy.on('exception', function(sender, response, operation, opts) {
// assign error to scope
this.error = Ext.decode(response.responseText);
}, scope, { single: true });
// do request
return store.proxy.doRequest(operation, this.onProxyValidate, scope);
},
// doRequest callback
onProxyValidate: function(operation) {
if (operation.action !== "validate") {
return;
}
// if validation was successful then there is nothing to do
if (this.error == undefined || this.error.success) {
return;
}
var errors = this.error.errors;
var plugin = this.plugin;
var grid = plugin.grid;
// this is private member
var columns = grid.headerCt.getGridColumns();
Ext.each(operation.records, function(record){
Ext.each(errors, function(error) {
// search column by dataIndex
var column = Ext.Array.filter(columns, function(c) { return c.dataIndex == error.dataIndex; })[0];
// get editor
var editor = column.getEditor();
// check if value in editor is still the same
if (editor.getValue().toString() == record.get(column.dataIndex).toString()) {
// set properties on editor, which will be accessed from validator method
editor.errorValue = editor.getValue();
editor.errorMessage = error.message;
// editor.setActiveError(error.message);
}
});
}, this);
plugin.editor.onFieldChange();
}
});
// Extended plugin; only difference is that it creates ExtRowEditor instead of RowEditor
Ext.define('Ext.grid.plugin.ExtRowEditing', {
extend: 'Ext.grid.plugin.RowEditing',
initEditor: function() {
var me = this,
grid = me.grid,
view = me.view,
headerCt = grid.headerCt;
return Ext.create('Ext.grid.ExtRowEditor', {
autoCancel: me.autoCancel,
errorSummary: me.errorSummary,
fields: headerCt.getGridColumns(),
hidden: true,
// keep a reference..
editingPlugin: me,
renderTo: view.el
});
}
});
And in proxy you should create validation
method:
var store = Ext.create('Ext.data.Store', {
proxy: {
type: 'ajax',
api:
{
read: 'api/read.php',
update: 'api/update.php',
create: 'api/create.php',
destroy: 'api/destroy.php',
validate: 'api/validate.php' // validation method
},
reader: {
type: 'json',
root: 'data'
}
}
});
Here is working sample.
Upvotes: 0