Onkelborg
18 Sep 2010, 12:53 AM
Hi!
This is my first post on this forum :) I've been using ExtJS for a few weeks now, and I've purchased a license to use ExtJS + Ext Designer within two weeks. I love it :)
However, much like with ASP.NET (which is what I use on the server-side), ExtJS isn't ready for everything. I make my own customizations everywhere, extensionmethods and T4-templates.. :)
In my case, I got a problem when I had an EditorGridPanel, which, of course, worked like a charm, if it wasn't for one tiny detail: how to enable display of server validation errors?
I found a thread with a rather malfunctioning solution, however, still a solution: http://www.sencha.com/forum/showthread.php?87570-Store-save-with-server-side-validation-errors&highlight=server+side+validation
I wasn't satisfied with that. Time to start digging documentation :)
JSON from server from my not so successful, restful:
{
"success": false,
"errors": {
"LastName": "Fill in your lastname!",
"ZipCode": "Do you know what a zip code is?"
}
}
Theory:
Before writing, map the json data to the record
In exception, get the json data, and use the map to..
Get the erroneous record
Get the rowIndex for the record
Get all columns that's editable
Get all errors from the server
For each erroneous column, get the errormessage and colIndex
Get the element, and the first child
Mark as "invalid" and set the error message
And the opposite for the good ones
That's pretty much it :) (And it works for both create and update, I've modified the example I mentioned ;) )
Code:
// Oskar Johansson, http://onkelborg.com
activateGridValidation = function (grid) {
var store = grid.getStore();
var mapRecordToRequestJsonData = [];
var mapRecordToRequestRecord = [];
var storeOnBeforeSave = function (store, data) {
mapRecordToRequestJsonData = [];
mapRecordToRequestRecord = [];
};
var storeOnBeforeWrite = function (dataProxy, action, rs, params) {
mapRecordToRequestJsonData.push(params.jsonData);
mapRecordToRequestRecord.push(rs);
};
var storeOnException = function (dataProxy, type, action, options, response, arg) {
if (action == "create" || action == "update") {
var erroneousObject = mapRecordToRequestRecord[mapRecordToRequestJsonData.indexOf(options.jsonData)];
var rowIndex = store.indexOf(erroneousObject);
var colModel = grid.getColumnModel();
var gridView = grid.getView();
var errorsInner;
var errors = response.raw ? response.raw.errors : ((errorsInner = Ext.decode(response.responseText)) ? errorsInner.errors : null);
var editableColumns = [];
for (var i = 0; i < colModel.getColumnCount(); i++) {
var column = colModel.getColumnById(colModel.getColumnId(i));
if (column.getCellEditor(rowIndex)) {
editableColumns.push(colModel.getDataIndex(i));
}
}
if (errors) {
var erroneousColumns = [];
for (var x in errors) {
erroneousColumns.push(x);
}
for (var i = 0; i < erroneousColumns.length; i++) {
editableColumns.splice(editableColumns.indexOf(erroneousColumns[i]), 1);
}
for (var i = 0; i < erroneousColumns.length; i++) {
var errKey = erroneousColumns[i];
var colIndex = colModel.findColumnIndex(errKey);
var msg = errors[errKey];
var cell = gridView.getCell(rowIndex, colIndex);
var cellElement = Ext.get(cell);
var cellInnerElement = cellElement.first();
cellInnerElement.addClass("x-form-invalid");
cellInnerElement.set({ qtip: msg });
}
}
for (var i = 0; i < editableColumns.length; i++) {
var colIndex = colModel.findColumnIndex(editableColumns[i]);
var cell = gridView.getCell(rowIndex, colIndex);
var cellElement = Ext.get(cell);
var cellInnerElement = cellElement.first();
cellInnerElement.removeClass("x-form-invalid");
cellInnerElement.set({ qtip: "" });
}
}
};
store.proxy.on("exception", storeOnException);
store.proxy.on("beforewrite", storeOnBeforeWrite);
store.on("beforesave", storeOnBeforeSave);
grid.on("destroy", function () {
store.proxy.un("exception", storeOnException);
store.proxy.un("beforewrite", storeOnBeforeWrite);
store.un("beforesave", storeOnBeforeSave);
});
};
Feel free to use it, if you want to, however, there are som quirks I know about:
It wont survive you changing store for the grid
I've only tested this against a restful store, I suspect this wont work if it isn't restful
This is my first post on this forum :) I've been using ExtJS for a few weeks now, and I've purchased a license to use ExtJS + Ext Designer within two weeks. I love it :)
However, much like with ASP.NET (which is what I use on the server-side), ExtJS isn't ready for everything. I make my own customizations everywhere, extensionmethods and T4-templates.. :)
In my case, I got a problem when I had an EditorGridPanel, which, of course, worked like a charm, if it wasn't for one tiny detail: how to enable display of server validation errors?
I found a thread with a rather malfunctioning solution, however, still a solution: http://www.sencha.com/forum/showthread.php?87570-Store-save-with-server-side-validation-errors&highlight=server+side+validation
I wasn't satisfied with that. Time to start digging documentation :)
JSON from server from my not so successful, restful:
{
"success": false,
"errors": {
"LastName": "Fill in your lastname!",
"ZipCode": "Do you know what a zip code is?"
}
}
Theory:
Before writing, map the json data to the record
In exception, get the json data, and use the map to..
Get the erroneous record
Get the rowIndex for the record
Get all columns that's editable
Get all errors from the server
For each erroneous column, get the errormessage and colIndex
Get the element, and the first child
Mark as "invalid" and set the error message
And the opposite for the good ones
That's pretty much it :) (And it works for both create and update, I've modified the example I mentioned ;) )
Code:
// Oskar Johansson, http://onkelborg.com
activateGridValidation = function (grid) {
var store = grid.getStore();
var mapRecordToRequestJsonData = [];
var mapRecordToRequestRecord = [];
var storeOnBeforeSave = function (store, data) {
mapRecordToRequestJsonData = [];
mapRecordToRequestRecord = [];
};
var storeOnBeforeWrite = function (dataProxy, action, rs, params) {
mapRecordToRequestJsonData.push(params.jsonData);
mapRecordToRequestRecord.push(rs);
};
var storeOnException = function (dataProxy, type, action, options, response, arg) {
if (action == "create" || action == "update") {
var erroneousObject = mapRecordToRequestRecord[mapRecordToRequestJsonData.indexOf(options.jsonData)];
var rowIndex = store.indexOf(erroneousObject);
var colModel = grid.getColumnModel();
var gridView = grid.getView();
var errorsInner;
var errors = response.raw ? response.raw.errors : ((errorsInner = Ext.decode(response.responseText)) ? errorsInner.errors : null);
var editableColumns = [];
for (var i = 0; i < colModel.getColumnCount(); i++) {
var column = colModel.getColumnById(colModel.getColumnId(i));
if (column.getCellEditor(rowIndex)) {
editableColumns.push(colModel.getDataIndex(i));
}
}
if (errors) {
var erroneousColumns = [];
for (var x in errors) {
erroneousColumns.push(x);
}
for (var i = 0; i < erroneousColumns.length; i++) {
editableColumns.splice(editableColumns.indexOf(erroneousColumns[i]), 1);
}
for (var i = 0; i < erroneousColumns.length; i++) {
var errKey = erroneousColumns[i];
var colIndex = colModel.findColumnIndex(errKey);
var msg = errors[errKey];
var cell = gridView.getCell(rowIndex, colIndex);
var cellElement = Ext.get(cell);
var cellInnerElement = cellElement.first();
cellInnerElement.addClass("x-form-invalid");
cellInnerElement.set({ qtip: msg });
}
}
for (var i = 0; i < editableColumns.length; i++) {
var colIndex = colModel.findColumnIndex(editableColumns[i]);
var cell = gridView.getCell(rowIndex, colIndex);
var cellElement = Ext.get(cell);
var cellInnerElement = cellElement.first();
cellInnerElement.removeClass("x-form-invalid");
cellInnerElement.set({ qtip: "" });
}
}
};
store.proxy.on("exception", storeOnException);
store.proxy.on("beforewrite", storeOnBeforeWrite);
store.on("beforesave", storeOnBeforeSave);
grid.on("destroy", function () {
store.proxy.un("exception", storeOnException);
store.proxy.un("beforewrite", storeOnBeforeWrite);
store.un("beforesave", storeOnBeforeSave);
});
};
Feel free to use it, if you want to, however, there are som quirks I know about:
It wont survive you changing store for the grid
I've only tested this against a restful store, I suspect this wont work if it isn't restful