0

I have a registration form, and i want to dynamically check for the submitted user name availability using AJAX. So far i've made a input field with an OnKeyUp event which calls a function named reg_un_check(); Problem is, at the current setting, which works fine, the function runs every key stroke. I wanna make some kind of "delay" between the keystrokes and the function call to let the user finish typing and save some bandwidth. I tried using SetTimeout() but it only delays the time it takes between the AJAX requests. This is what i've made so far:

Input Field:

<input type="text" value="user name" id="reg_un" onclick="reg_un_in()" onblur="reg_un_out()" onkeyup="reg_un_check()">
<div class="alerts" id="reg_un_alert"></div> // div that pops out if the UN isnt valid
<div class="reg_unc" id="reg_unc_alert"></div> // div that pops out when its checking for the availability

The AJAX function:

function reg_un_check(){
    if(reg_un.value.length > 1){
        $("#reg_un_alert").slideUp(150);
        var un_data = "un=" + reg_un.value;
        $("#reg_unc_alert").slideDown(150,function () {
            var un_check = setTimeout(function(){
                xmlhttp.onreadystatechange=function() {
                    if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
                        reg_unc_alert.innerHTML = xmlhttp.responseText;
                    }                                               
                    else{
                        reg_unc_alert.innerHTML = "checking for availability...";                           
                    }
                };
                xmlhttp.open("POST",'un_check.php',true);
                xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
                xmlhttp.send(un_data);                      
            },2000);            
        });
    }
    else{
        $("#reg_unc_alert").slideUp(150);
        reg_un_alert.innerHTML = "the user name must be at least 2 characters long";
        $("#reg_un_alert").slideDown(150);
    }
}

Can anyone suggest a different or a better way to do that? Thanks.

Alex
  • 13
  • 2
  • Because you do not cancel the timeout.... Bunch of dupes with the same problem, time to find one. – epascarello Oct 17 '14 at 20:05
  • Not a fan of this one: http://stackoverflow.com/questions/7373023/throttle-event-calls-in-jquery still looking for a better one. – epascarello Oct 17 '14 at 20:07
  • 3
    it always amazes me that some people will use jQuery for the DOM, but then hand-craft `XMLHttpRequest` objects to do their AJAX. – Alnitak Oct 17 '14 at 20:09
  • NB: the keyword you need to search for is _debounce_ – Alnitak Oct 17 '14 at 20:09
  • http://stackoverflow.com/questions/4220126/run-javascript-function-when-user-finishes-typing-instead-of-on-key-up – epascarello Oct 17 '14 at 20:09
  • @Alnitak what do you mean? i only used jQuery for the sliding effects... – Alex Oct 17 '14 at 20:16
  • @Alex I mean that jQuery includes a much of AJAX related functions that would make that part of your code utterly trivial. `$.post('un_check.php', {un: reg_un.value}).then(function(html) { reg_unc_alert.innerHTML = html });` – Alnitak Oct 17 '14 at 20:18

1 Answers1

1

It's a very common concept in javascript, called debouncing, lodash library has it: https://lodash.com/docs#debounce

A simple way to make it your self is like this:

var timeoutId;
function debounceFunction() {
   clearTimeout(timeoutId); //no worries if timeoutid is undefined
   timeoutId = setTimeout(delayedWorkFunction, delay);
}

A more complicated way, but a more generalized way to do it is to have a function that receives a function and a delay, and returns a function that on invocation will execute that function with the delay and cancel calls that were made before the delay has passed (i.e. what lodash debounce function does).

 function debounce(cb, delay) {
      var tId;
      var retFunc = function() {
          clearTimeout(tId);
          setTimeout(cb, delay);
      }
      return retFunc;
  }

function work() {
     //your logic here
}

var delayedWork = debounce(work, 150);
//now calling delayedWork will do what you want

Hope I didn't over complicate it.

PiniH
  • 1,901
  • 13
  • 20
  • Just FYI, debouncing and throttling are two slightly different concepts. Debouncing waits until an action hasn't been repeated in a certain amount of time (which is what you are showing correctly), throttling limits the amount of times an action can be repeated in a given amount of time. http://drupalmotion.com/article/debounce-and-throttle-visual-explanation – Jesse Kernaghan Oct 17 '14 at 20:16
  • Oh ok, now the names make sense :) Edited to reflect what you said. – PiniH Oct 18 '14 at 07:39