Beside the client side error handling this (well written) article described, it is first of all essential, that the server side indicates errors in a proper way. Many scripting languages like PHP were made for producing HTML. Now that they have to produce an XML document for the Ajax-client you have to customize the error handling to be integrated into the XML document and/or generate the right HTTP response code.
Copy & paste the code below to embed this comment.
Maarten van Baarsel
Having a coding background, there are some nits with the code that wouldn’t have passed a code review. Considering the ‘leader-of-the-pack’ status of ALA, people will copy-paste examples given here, and why have them copy-paste less-then-perfect examples? :)
The test in the ‘keep users informed’ example should be rewritten in reverse (if (request.status!=200){ error(…);}). Saves an indent and unobfuscates code.
In the PHP-code example; after an exit() in an if()-statement there is no need for an else. Saves an indent.
The “second example” that pops up a box ‘please wait’ is a very nice touch indeed!
Copy & paste the code below to embed this comment.
Peter Quinsey
Eugen, Maarten, thanks for the feedback.
I tried to minimize specific details of a server-side error-handling implementation, aiming instead to stick to general principles which will apply across all platforms, languages, and/or frameworks.
In that light, I tried to keep the code examples as skeletal as possible. I would much rather have someone read the article and say “ah, I know how I can improve my app’s error handling”—but of course this is the internet, and people will copy and paste. Thanks for the code tweaks.
sorry, should have expanded the first part of my comment: if the function perform_ajax_action fails to create an ajax request, it should return false, not true…
more generally: if i call a function and the function fails to perform, it should return false, not true (from a good practice/clarity point of view). hence, imho, it should be:
function perform_ajax_action(){
if ( !request = createAjaxRequest() ){
return false; // abort Ajax attempt, submit form
}
// proceed with your regular Ajax functionality
// …
return true; // do not submit the form
}
I agree to Patrick, that it’s common sense for developers to return false if the execution of a method failed. Same is for JavaScript onSubmit event handlers, because they were meant for checking form values and then when the check failed you should return false and the form should not be submitted.
With Ajax it’s vice versa, the form should not be submitted if everything is ok.
A solution to this is the usage of an onClick event handler on the submit button that triggers the Ajax action and an onSubmit method that just checks for errors of the Ajax action. Then the true / false logic is right again.
Copy & paste the code below to embed this comment.
brian smith
Do you typically write a single server-side handler that works for ajax and standard form posts? If so, how do you detect which occurs, so you return full HTML on a form post, or a redirect, rather than the Ajax xml snippet?
Copy & paste the code below to embed this comment.
Peter Quinsey
Patrick and Frank nail the return value problem on the head: a function that fails should return false, but an onsubmit’s event handler should return true if the Ajax functionality fails. So at some point you’re going to have a logical disconnect in your code, whether it’s returning false upon success or negating the return value at the event level.
One way of getting around this: instead of triggering the form submission using a return value, trigger the form submission directly from within your function:
function perform_ajax_action() {
if (!we_support_ajax()) {
document.forms0.submit();
return false;
}
// rest of Ajax functionality goes here
return false;
}
Yes, you’re still returning false upon success, which is logically incorrect, but the logical importance of the return value is diminished since we no longer depend on it to trigger form submission.
Copy & paste the code below to embed this comment.
Peter Quinsey
Do you typically write a single server-side handler that works for ajax and standard form posts? If so, how do you detect which occurs, so you return full HTML on a form post, or a redirect, rather than the Ajax xml snippet?
For a more complex implementation, this is a good idea. The ideal implementation would have three server-side components:
the server-side functionality
the Ajax interface to the functionality
the traditional interface to the functionality
How these are implemented depends on the scale of your app: separate files, separate functions, separate single lines of code.
There are a number of ways to detect whether to use the Ajax interface or the traditional interface. You could add an extra GET variable to the Ajax call to act as a flag. You could use POST for the traditional form submission instead of GET (semanticists may take issue with this, depending on what your form’s task is). Or you could just give each interface a separate file.
“beside the client side error handling this (well written) article described, it is first of all essential, that the server side indicates errors in a proper way. Many scripting languages like PHP were made for producing HTML. Now that they have to produce an XML document for the Ajax-client you have to customize the error handling to be integrated into the XML document and/or generate the right HTTP response co”
Copy & paste the code below to embed this comment.
Tony Gallagher
Its good to see someone giving some effort to error handling in ajax.
I tried searching for quite a while before resorting to my own experiments.
I thought some people out there might find this useful.
Any number of problems can arise which may result in communications problems
between your ajax application and the server and unfortunately the different
XMLHttpRequest objects do not handle them in a standard way.
The server may be offline or your route to the server may be down resulting in
not being able to establish a connection, a 30 second timeout is not the best
solution here.
opera 9 will call onreadystatechange with req.readyState=4 and req.status=0
firefox 1 will call onreadystatechange with req.readyState=4 and req.status exception
ie 6 will call onreadystatechange with req.readyState=4 and req.status=12029
Those are easily enough detected, use try and catch to handle the exception.
Your connection to the server could unexpectedly close due to network problems
or a server crash. These are much harder to deal with.
opera 9 will call onreadystatechange with req.readyState=4 and req.status=0
ie 6 will call onreadystatechange with req.readyState=4 and req.status=12152
firefox 1 will call onreadystatechange with req.readyState=4 and req.status=200
The firefox response is a big problem here, 200 is the HTTP status code sent by the
server to indicate success but firefox will give a status of 200 if the server disconnects
without sending any status code at all which means it is not reliable to use a 200 status code
as an indication of success. If we were posting a message on a bbs when the error occured then
firefow would indicate success but our message would not be posted.
So how should we detect a successful ajax request? a fully valid response document would be
one indication but not all ajax requests return a document, XML, JSON, plain text or anything.
We could use another status code but there are problems there too.
The code which should be returned if there is no document body is 204 “No Content”,
unfortunately if we return 204 then opera9 will not call onreadystatechange so our ajax
application does not see a response at all. IE6 will call onreadystatechange with
req.readyState=4 and req.status=1223 instead. Fortunately 202 “Accepted” does work reliably.
There are similar problems with HTTP status codes in the 500 range (Failure codes).
Believe it or not it is possible to code your ajax application to work reliably despite all
these problems but it helps if you know what to expect.
One highly useful technique is the use of “unit tests”:http://en.wikipedia.org/wiki/Unit_test for your Javascript classes. Many developers working in other languages/problem domains rely heavily on unit tests to ensure things work the Way They Should. A unit test is a methodology for taking program “units” (modules, classes… basically any encapsulated group of code) and subjecting it to a comprehensive set of tests, which determine whether it behaves as the author(s) of the code intended.
There are some Javascript unit testing frameworks (“JSUnit”:http://jsunit.net , the Scriptaculous “testing components”:http://wiki.script.aculo.us/scriptaculous/show/Testing ) that can help you accomplish this.
I have found unit tests can help with improving AJAX apps. A unit test cannot be comprehensive of all the millions of weird ways a user might use your app. But, unit testing helps me remember to encapsulate functionality, even when writing JS, and to provide consistent, well documented interfaces in my classes. The biggest gain, though, is in troubleshooting. If I find an error, and know that the class the functionality relies on is passing its tests, it is typically safe to assume that the issue isn’t a coding issue in the class itself, but lies somewhere else.
For a concrete example, I was recently having a problem with an AJAX app I’m working on that deals with statistical data manipulation. Because I’d written tests for my data manipulation classes, when I hit an error, I was able to quickly ascertain that the classes were manipulating the data as specified but that my event registration code was firing prior to the creation of the elements it was supposed to be attached to. Nothing fancy there, but given how easy it is to run into silent errors in AJAX scripting, any methodology that reveals problems rapidly and before an error becomes a Real Problem is a useful methodology.
I’m already using the “hijaxing”(nice term) technique successfully but I’m very impressed with the second example. Timeouts in ajax apps ARE a pain in the rear and your solution for handling it is really nice.
The most used nav button in any website is the browser’s back button. Clicking “back” when something goes wrong is a strategy that each of us employs.
We expect to see pages reload too. These are conventions that we have learned in the first 15 years or so of the web. We are going to have to unlearn them, however, if AJAX and other Rich Internet App techniques are to prevail.
For this shift in the web design paradigm to occur, designers and developers will have to meet half-way. Until now, I wasn’t sure how this was going to happen.
But, you’re right, it’s as simple as adding a timer to the web page and passing messages to the user, depending on how long they have been waiting.
One difficulty with the temporal approach, however, is that users on different connection speeds will have different wait times. That could pose a problem for international sites.
22 Reader Comments
Back to the ArticleEugen Schneider
Beside the client side error handling this (well written) article described, it is first of all essential, that the server side indicates errors in a proper way. Many scripting languages like PHP were made for producing HTML. Now that they have to produce an XML document for the Ajax-client you have to customize the error handling to be integrated into the XML document and/or generate the right HTTP response code.
Maarten van Baarsel
Having a coding background, there are some nits with the code that wouldn’t have passed a code review. Considering the ‘leader-of-the-pack’ status of ALA, people will copy-paste examples given here, and why have them copy-paste less-then-perfect examples? :)
The “second example” that pops up a box ‘please wait’ is a very nice touch indeed!
Peter Quinsey
Eugen, Maarten, thanks for the feedback.
I tried to minimize specific details of a server-side error-handling implementation, aiming instead to stick to general principles which will apply across all platforms, languages, and/or frameworks.
In that light, I tried to keep the code examples as skeletal as possible. I would much rather have someone read the article and say “ah, I know how I can improve my app’s error handling”—but of course this is the internet, and people will copy and paste. Thanks for the code tweaks.
patrick lauke
logically, if perform_ajax_action is successful, it should return true…so
onsubmit=“return perform_ajax_action();”
should be
onsubmit=“return !perform_ajax_action();”
Sander Aarts
@patrick: I guess that
if ( !request = createAjaxRequest() ) {}
allready did that trick here.
patrick lauke
sorry, should have expanded the first part of my comment: if the function perform_ajax_action fails to create an ajax request, it should return false, not true…
more generally: if i call a function and the function fails to perform, it should return false, not true (from a good practice/clarity point of view). hence, imho, it should be:
function perform_ajax_action(){
if ( !request = createAjaxRequest() ){
return false; // abort Ajax attempt, submit form
}
// proceed with your regular Ajax functionality
// …
return true; // do not submit the form
}
and then deal with it via
onsubmit=”?return !perform_ajax_action();”?
Frank Fischer
I agree to Patrick, that it’s common sense for developers to return false if the execution of a method failed. Same is for JavaScript onSubmit event handlers, because they were meant for checking form values and then when the check failed you should return false and the form should not be submitted.
With Ajax it’s vice versa, the form should not be submitted if everything is ok.
A solution to this is the usage of an onClick event handler on the submit button that triggers the Ajax action and an onSubmit method that just checks for errors of the Ajax action. Then the true / false logic is right again.
Frank Fischer
My last comment appears as the first comment, but it was actually an answer to “should have expanded my previous comment” by Patrick. Confused,
Frank.
Sander Aarts
You’re probably right. It seems more logical.
cheers
brian smith
How do you write a single server-side action that:
1) returns xml for valid ajax request
2) returns full html/xhtml,or forwards to full url, if standard form post?
brian smith
Do you typically write a single server-side handler that works for ajax and standard form posts? If so, how do you detect which occurs, so you return full HTML on a form post, or a redirect, rather than the Ajax xml snippet?
Peter Quinsey
Patrick and Frank nail the return value problem on the head: a function that fails should return false, but an onsubmit’s event handler should return true if the Ajax functionality fails. So at some point you’re going to have a logical disconnect in your code, whether it’s returning false upon success or negating the return value at the event level.
One way of getting around this: instead of triggering the form submission using a return value, trigger the form submission directly from within your function:
function perform_ajax_action() {
if (!we_support_ajax()) {
document.forms0.submit();
return false;
}
// rest of Ajax functionality goes here
return false;
}
Yes, you’re still returning false upon success, which is logically incorrect, but the logical importance of the return value is diminished since we no longer depend on it to trigger form submission.
Peter Quinsey
Well, it looked good in the preview. But you get the idea.
Peter Quinsey
For a more complex implementation, this is a good idea. The ideal implementation would have three server-side components:
How these are implemented depends on the scale of your app: separate files, separate functions, separate single lines of code.
There are a number of ways to detect whether to use the Ajax interface or the traditional interface. You could add an extra GET variable to the Ajax call to act as a flag. You could use POST for the traditional form submission instead of GET (semanticists may take issue with this, depending on what your form’s task is). Or you could just give each interface a separate file.
james williams
“beside the client side error handling this (well written) article described, it is first of all essential, that the server side indicates errors in a proper way. Many scripting languages like PHP were made for producing HTML. Now that they have to produce an XML document for the Ajax-client you have to customize the error handling to be integrated into the XML document and/or generate the right HTTP response co”
I dont think you understand ajax.
Tony Gallagher
Its good to see someone giving some effort to error handling in ajax.
I tried searching for quite a while before resorting to my own experiments.
I thought some people out there might find this useful.
Any number of problems can arise which may result in communications problems
between your ajax application and the server and unfortunately the different
XMLHttpRequest objects do not handle them in a standard way.
The server may be offline or your route to the server may be down resulting in
not being able to establish a connection, a 30 second timeout is not the best
solution here.
opera 9 will call onreadystatechange with req.readyState=4 and req.status=0
firefox 1 will call onreadystatechange with req.readyState=4 and req.status exception
ie 6 will call onreadystatechange with req.readyState=4 and req.status=12029
Those are easily enough detected, use try and catch to handle the exception.
Your connection to the server could unexpectedly close due to network problems
or a server crash. These are much harder to deal with.
opera 9 will call onreadystatechange with req.readyState=4 and req.status=0
ie 6 will call onreadystatechange with req.readyState=4 and req.status=12152
firefox 1 will call onreadystatechange with req.readyState=4 and req.status=200
The firefox response is a big problem here, 200 is the HTTP status code sent by the
server to indicate success but firefox will give a status of 200 if the server disconnects
without sending any status code at all which means it is not reliable to use a 200 status code
as an indication of success. If we were posting a message on a bbs when the error occured then
firefow would indicate success but our message would not be posted.
So how should we detect a successful ajax request? a fully valid response document would be
one indication but not all ajax requests return a document, XML, JSON, plain text or anything.
We could use another status code but there are problems there too.
The code which should be returned if there is no document body is 204 “No Content”,
unfortunately if we return 204 then opera9 will not call onreadystatechange so our ajax
application does not see a response at all. IE6 will call onreadystatechange with
req.readyState=4 and req.status=1223 instead. Fortunately 202 “Accepted” does work reliably.
There are similar problems with HTTP status codes in the 500 range (Failure codes).
Believe it or not it is possible to code your ajax application to work reliably despite all
these problems but it helps if you know what to expect.
David Eads
One highly useful technique is the use of “unit tests”:http://en.wikipedia.org/wiki/Unit_test for your Javascript classes. Many developers working in other languages/problem domains rely heavily on unit tests to ensure things work the Way They Should. A unit test is a methodology for taking program “units” (modules, classes… basically any encapsulated group of code) and subjecting it to a comprehensive set of tests, which determine whether it behaves as the author(s) of the code intended.
There are some Javascript unit testing frameworks (“JSUnit”:http://jsunit.net , the Scriptaculous “testing components”:http://wiki.script.aculo.us/scriptaculous/show/Testing ) that can help you accomplish this.
I have found unit tests can help with improving AJAX apps. A unit test cannot be comprehensive of all the millions of weird ways a user might use your app. But, unit testing helps me remember to encapsulate functionality, even when writing JS, and to provide consistent, well documented interfaces in my classes. The biggest gain, though, is in troubleshooting. If I find an error, and know that the class the functionality relies on is passing its tests, it is typically safe to assume that the issue isn’t a coding issue in the class itself, but lies somewhere else.
For a concrete example, I was recently having a problem with an AJAX app I’m working on that deals with statistical data manipulation. Because I’d written tests for my data manipulation classes, when I hit an error, I was able to quickly ascertain that the classes were manipulating the data as specified but that my event registration code was firing prior to the creation of the elements it was supposed to be attached to. Nothing fancy there, but given how easy it is to run into silent errors in AJAX scripting, any methodology that reveals problems rapidly and before an error becomes a Real Problem is a useful methodology.
Dave Kinsella
I’m already using the “hijaxing”(nice term) technique successfully but I’m very impressed with the second example. Timeouts in ajax apps ARE a pain in the rear and your solution for handling it is really nice.
Michael Heraghty
The most used nav button in any website is the browser’s back button. Clicking “back” when something goes wrong is a strategy that each of us employs.
We expect to see pages reload too. These are conventions that we have learned in the first 15 years or so of the web. We are going to have to unlearn them, however, if AJAX and other Rich Internet App techniques are to prevail.
For this shift in the web design paradigm to occur, designers and developers will have to meet half-way. Until now, I wasn’t sure how this was going to happen.
But, you’re right, it’s as simple as adding a timer to the web page and passing messages to the user, depending on how long they have been waiting.
One difficulty with the temporal approach, however, is that users on different connection speeds will have different wait times. That could pose a problem for international sites.
sumathi magesh
I am using ajax for submitting the form.
I received Error 12002 in IE .
I want to know what is the reason.
Please reply me .
webmaster -elite
Really nice article. Thanks.
website design
It did seems far more logical. Finne with preview but… Still if you are saying then I’ll try again.Thanks for your valuable presentation.
Alex