PDA

View Full Version : Catch errors in JSON decoding for Ext.form.BasicForm



jeroenooms
15 Mar 2010, 8:40 PM
I am using a file upload form, similar to the example here (http://www.extjs.com/deploy/dev/examples/form/file-upload.html). Basically it is a formpanel with fileUpload:true, for which I call the submit() function.

The server reads in the file, and returns summary in JSON. However, unfortunately the server does not always return perfectly valid JSON, which results in client errors.

Is it possible to catch json decoding errors in the success callback? For my ajax requests, I usually wrap a try catch block around the Ext.util.JSON.decode() function, but for forms, the response is decoded as JSON by default.

Animal
19 Mar 2010, 11:05 PM
It's not decoded.

You can step through the code which scrapes response text from the target iframe to see exactly what is happening.

Go into Firebug, switch to ext-all-debug.js, search for some string (eg "if(/textarea/i.test") which brings up the following code area:



function cb(){
var me = this,
// bogus response object
r = {responseText : '',
responseXML : null,
argument : o.argument},
doc,
firstChild;

try{
doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
if(doc){
if(doc.body){
if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea
r.responseText = firstChild.value;
}else{
r.responseText = doc.body.innerHTML;
}
}
//in IE the document may still have a body even if returns XML.
r.responseXML = doc.XMLDocument || doc;
}
}
catch(e) {}


It's the "onload" handler for the iframe which receives the response. Set a breakpoint at the top, and step through watching what happens you your response. You can follow control all the way back into your code.

jeroenooms
20 Mar 2010, 7:07 PM
It is decoded when the callback functions are called. For 3.1.1, at line 9632 of ext-all-debug.js the line runCallback(o.success, o.scope, [r, o]); is called, which then via via calls the method 'handleResponse', as defined on line 63298:

handleResponse : function(response){
if(this.form.errorReader){
var rs = this.form.errorReader.read(response);
var errors = [];
if(rs.records){
for(var i = 0, len = rs.records.length; i < len; i++) {
var r = rs.records[i];
errors[i] = r.data;
}
}
if(errors.length < 1){
errors = null;
}
return {
success : rs.success,
errors : errors
};
}
return Ext.decode(response.responseText);
}
I don't see the logic in this procedure: either you supply a custom error reader, in which case it will only return {success:rs.success, errors : errors} and you lose your data, or you don't supply one, in which case it will return simply the decoded responseText.

Animal
20 Mar 2010, 10:55 PM
I see. Your requirement is a common one I think and similar to this guy's, except that you need to get in a little earlier: http://www.extjs.com/forum/showthread.php?t=94740

Try this



Ext.override(Ext.form.Action.Submit, {
success : function(response){
if (this.form.fireEvent('beforeactioncomplete', this.form, response) !== false) {
var result = this.processResponse(response);
if(result === true || result.success){
this.form.afterAction(this, true);
return;
}
if(result.errors){
this.form.markInvalid(result.errors);
}
this.failureType = Ext.form.Action.SERVER_INVALID;
this.form.afterAction(this, false);
}
}
});


In fact, I think the beforeactioncomplete should ideally be called from the next line and pass the decoded result, but for your case, the above will get you going (But keep checking the API docs in case they ever fix this!)

The Ext.form.Action.* classes should fire exception events through their client BasicForms if anything goes wrong (like JSON or XML syntax errors)

This has been discussed before IIRC. People have pointed out that there's no error trapping when processing form return packets. It really needs addressing along with adding events on succcessful response decoode.

Animal
20 Mar 2010, 11:10 PM
The easiest thing might be to provide your own custom Reader for the form.

It doesn't need to be an Ext one. Just an object with a read function in it which accepts an XHR object, and does whatever you want,, and returns



{
success: true/false,
records: [{ // Optional, only if there were field errors reported
data: {
id: 'fieldName',
msg: 'Why it is invalid'
}
}, [{
data: {
id: 'fieldName',
msg: 'Why it is invalid'
}
}...]
}


And you can obviously poke your own custom data in there and retrieve it in your afteraction handler or success/fail handlers.

I think the Ext.form.Action classes need a bit of updating.

jeroenooms
20 Mar 2010, 11:33 PM
And you can obviously poke your own custom data in there and retrieve it in your afteraction handler or success/fail handlers.
I tried this, but this is exactly the problem. The 'handleResponse' function that I quoted above, in the end only extracts the success and errors:

return {
success : rs.success,
errors : errors
};
all other data is lost. Whenever I specify an errorReader, the callbacks don't work anymore. And afaik the 'reader' property that is documented is completely ignored for non-ajax forms.

Animal
20 Mar 2010, 11:54 PM
non-ajax? You are using Ajax. You can implement your own reader.

jeroenooms
21 Mar 2010, 2:38 PM
You override did not do the trick for me, but this one did in my case:

Ext.override(Ext.form.Action.Submit, {
handleResponse : function(response){
if(this.form.errorReader){
var rs = this.form.errorReader.read(response);
var errors = [];
if(rs.records){
for(var i = 0, len = rs.records.length; i < len; i++) {
var r = rs.records[i];
errors[i] = r.data;
}
}
if(errors.length < 1){
errors = null;
}
return {
success : rs.success,
errors : errors
};
}
try{
return Ext.decode(response.responseText);
}catch(e){
alert('Error in decoding server response. Your data set might contain system characters like backslashes. Please try to avoid this.');
console.log(response.responseText);
return false;
}
}
});

JoyfulBobHome
6 Apr 2010, 9:24 AM
Interesting post; thanks. Could this be adapted to trap errors in a grid's JSON response? Our issue is the grid JSON fails if there's a carriage return (ENTER key) in a field's value. The entire response fails and nothing is loaded into the grid/store.

Would I use Ext.data.Store.exception? And/or add a JsonReader.jsonData or readResponse?

jmann
15 Nov 2011, 7:48 AM
Love that I can override the handleResponse for the file upload issue I was encountering.
Is there any future considerations of handling and raising this to the formSubmit object to trap errors rather than throwing an Ext.Error.raise?

-john-