Wednesday, July 16, 2014

Ajax (+ jQuery) + 303 Redirect

As you might know browsers handle 30x responses on their own - that mean you won't be able to get easily in your callback information whether response contains form submission errors or is result of post-redirect-get success call.


Not any project can use latest cool technologies like AngularJS and many times you'll have to deal with old good HTML responses from server. If you want to give users single page like experience in some parts of your site, like login forms in fancy window, you'll probably looked into jQuery Ajax request possibilities or even better jQuery Forms.


Using jQuery Forms it's easy to submit html form via Ajax, you'll have to only add JS code to make it dynamic:


 <form id="loginForm" ... >
//your inputs here
<input type="submit" value="Log in!"/>
 </form>


 $(document).ready(function() {

// bind 'loginForm' and provide a simple callback function

  $('#loginForm').ajaxForm({
     target: '#loginForm',
       success: ajaxResponseHandler
    //some other properties

}
   );
 });
And that's it, your form is now dynamic. In above example target property is used to populate the result of the callback as a replacement for the form. So now you can in server backend return only the form with errors not the whole page.


This should do the trick for all the 'invalid login'/'not existing user' scenarios. But what if the result of login is success?


You'll expect get from the server 303 response (if you're using post-redirect-get pattern), but you won't be able to detect it in your callback handler as browser will do it upfront for you. See the example below:



Browser takes care of redirect response on its own.


So how to detect if the response is not form with errors to display, but regular page?


There are a few ways of doing this - you might include some 'meta marker' in result page and then try to find it via JS. Not hard, but ugly, isn't it?


Other popular solution is to change the header of response from server and use other status code, for instance some less common 2xx. This way browser won't process it and will pass the response to your handler. It would work, but I'm not fan of this solution.


I'm dealing with this problem differently. Instead of returning 303 redirect after successful form submission I return simple redirect.xml file:


<?xml version="1.0" encoding="utf-8" ?>
<redirect location="URI" />


Where URI is location where you want the user to go. You only need to add some code to your Ajax callback:


function ajaxResponseHandler(responseText, statusText, xhr, $form) {
 var jQueryResponse = $(responseText);
 if (typeof(jQueryResponse) == 'object') {
var newLocation = $(jQueryResponse).attr("location");
if (newLocation) {
  if (newLocation == "__refresh__") {
    location.reload();
    return;
  }
  else {
    location.href = newLocation;
    return;
  }
}
 }
 else {
//Your code here
 }
 // do sth else
}


The above code not only will do 'client side' redirect, but also you can set URI to be "__refresh__" and make the site only to refresh (if you had form in window, than there is no need to change current URL, it might only be enough to refresh the page).

I use this code to handle all Ajax forms, if there was error than target makes sure user will see new form with highlighted problems, if the user submitted valid form he will be redirected to the destination just as I planned.

No comments:

Post a Comment