views:

36

answers:

2

I am working on a way to autocomplete function to navigate through steps of a form. Here is the code that when 5 characters are entered into an input, it then moves to the next element. My delay is working great, but I don't have a way to stop it from completing if characters get deleted after 5 characters are entered. It just fires off the focus right after that no matter what has changed in the input.

Any thoughts?

var delay = (function(){
    var timer = 0;
    return function(callback, ms) {
        clearTimeout (timer);
        timer = setTimeout(callback, ms);
    }; 
})();

$('input').keyup(function(){
    if($(this).val().length == 5) {
        delay(function(){ $("#saveForm2").focus(); }, 2000 );  
    }
})
A: 

Each time you call delay(), you clobber your timeout handle, which means that you can't manage it after the fact. It also means that you're going to fire off a request every time you hit 5 characters, if I read that correctly. Try something like this:

var delayTimer;
var nextField = function() { $("#saveForm2").focus(); }
$('input').keyup(function(){
  clearTimeout(delayTimer);
  if($(this).val().length >= 5) {
    delayTimer = setTimeout(nextField, 2000);
  }
})

That'll a) fire off no more than 1 request unless you wait more than 2 seconds between keystrokes, and b) will cancel any pending request if you drop back under 5 characters before the timeout expires. As a bonus, it won't create a whole mess of anonymous functions.

Chris Heald
+3  A: 

If you're looking for an easy way to associate a timeout instance with an element, consider using jQuery's .data() method.

Something like this.

$('input').keyup(function() {
    var $th = $(this);
    var data = $th.data();
    if(data.timeout === undefined) {
        data.timeout = null;
    }
    if ($th.val().length == 5) {
        clearTimeout(data.timeout);
        data.timeout = setTimeout(function() {
            $("#saveForm2").focus();
        }, 2000);
    } else {
        clearTimeout(data.timeout);
    }
});​

I don't think the way you were using the closure was quite right. I think you would need to assign the handler to the element inside the closure as well, so it has a local reference to the instance.

EDIT: Made a little more efficient with earlier stored reference to data().

patrick dw