Pages

Monday, August 20, 2012

Jquery/Javascript method to handle real-time user input in a textfield


I recently ran across a problem where I needed to handle user input in a textfield in real-time. What I needed to do in my situation was to perform an AJAX call to my Drupal site as the user was typing into a textfield (to see if that value was available in the database). The main problem was that there were a few easy options for doing this in JQuery, but most of them were not good enough. Here are two of the options I tried.

The change or blur approach

The first and easiest option was to just perform the action using the Jquery .change() or .blur() method. This would basically run the AJAX request after the text-field loses focus. This would mean that after a user stopped typing they would need to click out of the text-field in order for the AJAX to run. This was not an acceptable solution as that is not the typical user behavior.

The keypress/keyup/keydown or input approach

I eventually stumbled on a way to run the AJAX after every key the user pressed. I could use something like the following line to accomplish this:
$('#edit-my-textfield', context).bind('input', function() {
  //my code goes here
});
This however runs the AJAX call after every single keypress. Because of the various validation I also needed to do on the text-field, this often caused unexpected and buggy results (the results of the AJAX calls did not always come back in the exact order they were executed if many keys were pressed rapidly). Again, this method was much closer, but it was to buggy and unreliable.

The "near" real-time solution

It took me awhile, but I finally came across a solution I can live with. There may be many other options out there to do this (if you know of any, please let me know), but this one seems to work fairly well.
I built all of this inside a simple Drupal 6 module. Here is and example of the related form information:
$form['my_fieldset'] = array(
  '#type' => 'fieldset', 
  '#title' => t('My Fieldset'), 
  '#weight' => 5, 
  '#collapsible' => FALSE, 
  '#collapsed' => FALSE,
);
$form['my_fieldset']['my_textfield'] = array(
  '#type' => 'textfield',
  '#title' => '',
  '#default_value' => "",
  '#size' => 30,
  '#maxlength' => 30,
  '#required' => TRUE,
  '#prefix' => "<div id='selection_wrapper'>",
  '#suffix' => "<div id='display_results'></div></div>",
);
I also used the hook_init() function to include the necessary Javascript and CSS files:
/**
 * Implements hook_init().
 */
function MYMODULE_init() {
  drupal_add_js(drupal_get_path('module', 'MYMODULE') .'/MYMODULE.js');
  drupal_add_css(drupal_get_path('module', 'MYMODULE') .'/MYMODULE.css');
}
Here is an example of the Javascript I used:
Drupal.behaviors.MYMODULE = function(context) {
  var myTimer = undefined;
  var delayTime = 1500; // should be in miliseconds.
 
  //should insert the throbber image and hide it
  $('#edit-my-textfield', context).bind('input', function() {
    $('#display_results').html('');
    $('#display_results').addClass('display-throbber');
 
    if (myTimer) {
        clearTimeout(myTimer);
    }
    my_val = $(this).val();
    myTimer = setTimeout('myfunction(my_val);', delayTime);
 
    return false;
  });
}
 
function myfunction(my_val) {
  //do whatever you want here
  //I used this function for my logic and AJAX calls
  $('#display_results').removeClass('display-throbber');
  $('#display_results').html('It works!, the textfield says: ' + my_val);
}
I also added some basic CSS to display the results. I added a simple loading/throbber image that is displayed during the AJAX requests. I created the animated GIF image athttp://ajaxload.info/. In the JavaScript above, I add and remove a class called "display-throbber" that will trigger the display of the loading image.
The above code uses a simple timer (set to 1.5 seconds) that will call a function (called "myfunction") if it expires. However, if a user types another character in the text-field, the timer gets reset. This allows the user to type in the text-field and only runs the code in the "myfunction" function when at least 1.5 seconds have elapsed. For the simple example above it may not seem necessary, however when making AJAX calls this provides reliable results and removes the need of unneccesary AJAX calls to the server. The only minor negative is the short delay before the "myfunction" code is run.
Note: In my original code I actually removed the "display-throbber" class in my AJAX response function, but since the above code is just a simple example, I added it to the "myfunction" function that is called after the timer elapses.
Here is the example CSS that goes along with the Drupal form and Javascript. It will probably need to be modified to fit your scenario but should provide a good starting point.
#selection-wrapper {
  overflow: auto;
}
#edit-my-textfield-wrapper {
  float:left;
}
#display_results {
  float: left;
  min-height: 15px;
  min-width: 100px;
  padding: 10px 0 0 10px;
  max-width: 280px;
}
#display_results.display-throbber {
  background: transparent url('./images/ajax-loader.gif') no-repeat center bottom;
}
So go ahead and provide some real-time features for your users when they enter data into text-fields. Meanwhile you can sleep soundly knowing that you are avoiding unnecessary AJAX requests, and providing a great user experience. In the future I will try to post a more detailed example of the AJAX requests interacting with the Drupal database.
One more thing, if you have not signed up for the newsletter yet... do it now! There will be some big happenings in the near future and if you are interested in learning more about Drupal and enjoy video formats, you will be glad you signed up.

No comments:

Post a Comment

Thanks for your comment.