User-Proofing Ajax

by Peter Quinsey

22 Reader Comments

Back to the Article
  1. 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.
  2. 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.
  3. 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.

    Copy & paste the code below to embed this comment.
  4. logically, if perform_ajax_action is successful, it should return true…so

    onsubmit=“return perform_ajax_action();”

    should be

    onsubmit=“return !perform_ajax_action();”

    Copy & paste the code below to embed this comment.
  5. @patrick: I guess that

    if ( !request = createAjaxRequest() ) {}

    allready did that trick here.

    Copy & paste the code below to embed this comment.
  6. 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();”?

    Copy & paste the code below to embed this comment.
  7. 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.
  8. 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.

    Copy & paste the code below to embed this comment.
  9. You’re probably right. It seems more logical.

    cheers

    Copy & paste the code below to embed this comment.
  10. 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?

    Copy & paste the code below to embed this comment.
  11. 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.
  12. 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.
  13. Well, it looked good in the preview.  But you get the idea.

    Copy & paste the code below to embed this comment.
  14. 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: 

    1. the server-side functionality
    2. the Ajax interface to the functionality
    3. 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.

    Copy & paste the code below to embed this comment.
  15. “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.

    Copy & paste the code below to embed this comment.
  16. 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.

    Copy & paste the code below to embed this comment.
  17. 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.

    Copy & paste the code below to embed this comment.
  18. 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.

    Copy & paste the code below to embed this comment.
  19. 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.

    Copy & paste the code below to embed this comment.
  20. 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 .

    Copy & paste the code below to embed this comment.
  21. Really nice article. Thanks.

    Copy & paste the code below to embed this comment.
  22. 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

    Copy & paste the code below to embed this comment.