Best, or at Least Better, Practices for Ajax Enabled Forms Using JQuery

For an internal project I am working on at the NIH we decided to make a nice Ajax enabled user edit form.  It’s quite simple.  When you first view the page there is a drop down box where you can select users.  When you choose a user, a JQuery trigger fires and an Ajax call is made to retrieve the user details so we can fill in the edit form.  This isn’t rocket science by today’s standards, but there are good ways and better ways to do it.

The first version of page was the simplest we could make it.  I’m a big fan of the KISS Principal so I didn’t want to add any bells and whistles until I saw that they were needed.  With the first implementation, you could scroll through the selection list of users and the edit form would tick through all their details as quick as you could want.  That was on my local development environment.  In the back of my mind I was thinking about how it would perform when we got it up on the production environment.  There the client and server wouldn’t be on the same PC and normal network lag would start to show up.  Since I didn’t have any real evidence that there would be a problem, I kept it simple.  Here is what the first version looked like:

$(document).ready (function (){
  $( ‘#usernameSelect’ ).change(function() {
    if (user_details_xhr) {
      user_details_xhr.abort();
    }

    showUserDetails( $( this ).find( ‘:selected’ ).attr(‘id’) );
});

function showUserDetails (userID) {
  jQuery.ajax({ url : “/api/editForm?id=” + userID,
                     success: function(data, status, jqXHR) {
                           if (status=“success”) {
                             $( ‘#user-details-pane’ ).html(data)}}
  });
}

Well, today I got to test it a bit on our staging server and it works pretty well.  Not perfect though.  If you select the top name on the list and hold the down arrow to scroll through the list you will see that the updates in the form lag far behind the selected user in the list.  When you get to the bottom of the name list the edit form keeps clicking through data for a second or two.  Worse is the case where you get a network glitch that delays the form update by a second or two.  That can be long enough for a user to actually click into the edit form thinking it has the updated info.  That’s not a nice user experience.

So here are two tweaks that I made to the process.  First off, before you even try to retrieve the new data, clear out the old info.  I did this with a couple lines that blank the input boxes in the edit form.  That way the user knows at a glance that the data hasn’t loaded in yet.  Second, make sure you abort your previous Ajax call before you start a new one.  That will prevent the user from seeing your form updates lagging behind the names in the selection list.  It doesn’t sound like much, but it really does look much nicer.  It will also save some hammering on the server if the call hasn’t been made yet.  To cancel your unneeded Ajax call, just call the abort() function on the xhr object that was returned by the jQuery.ajax() function. Here is the improved code:

var user_details_xhr = null;
$(document).ready (function (){
  $( ‘#usernameSelect’ ).change(function() {
    if (user_details_xhr) {
      user_details_xhr.abort();  // abort the previous showUserDetails() call
    }
    removePreviousUserDetails();  // clear any old data right now
    showUserDetails( $( this ).find( ‘:selected’ ).attr(‘id’) );
});

function removePreviousUserDetails()
  $( “#user-details-pane #username” ).val(“”);
  $( “#user-details-pane #fullname” ).val(“”);
  $( “#user-details-pane #displayname” ).val(“”);
  $( “#user-details-pane #email” ).val(“”);
  $( “#user-details-pane #passwordchange” ).val(“”);
  $( “#user-details-pane #passwordconfirm” ).val(“”);
}

function showUserDetails (userID) {
  user_details_xhr = jQuery.ajax({ url : “/api/editForm?&id=” + userID,
                                   success: function(data, status, jqXHR) {
                                     if (status=“success”) {
                                       $( ‘#user-details-pane’ ).html(data)}}
                                     });
}

 

So, why is this just a “better” practice, and not the best practice?  Well, mostly because I’m not a 10 year JavaScript expert so I’m sure that someone has a more elegant and comprehensive solution.   But also because I can think of some improvements that aren’t right for our situation but might be perfect for yours.  One possible upgrade would be to set a timer when you are scrolling through the list of names and not even try to update the edit form until they user settles on a name.  Another nice improvement would be to put a ‘loading’ spinner overtop the form while we load data.  Neither of these are really a good choice for our site because the data typically loads in so quickly that these would just slow the user down or be distractions.  For you though, those could be a really nice.