views:

1034

answers:

2

Hey all. I have a form which is submitted remotely when the various elements change. On a search field in particular i'm using a keyup to detect when the text in the field changes. The problem with this is that when someone types "chicken" then the form is submitted seven times, with only the last one counting.

What would be better is something like this

  • keyup detected - start waiting (for one second)

  • another keyup detected - restart waiting time

  • waiting finishes - get value and submit form

before i go off and code my own version of this (i'm really a backend guy with only a little js, i use jquery for everything), is there already an existing solution to this? It seems like it would be a common requirement. A jquery plugin maybe? if not, what's the simplest and best way to code this?

thanks, max

UPDATE - current code added for Dan (below)

Dan - this may be relevant. One of the jquery plugins i'm using on the page (tablesorter) requires this file - "tablesorter/jquery-latest.js", which, if included, leads to the same error with your code as before:

jQuery("input#search").data("timeout", null) is undefined http://192.168.0.234/javascripts/main.js?1264084467 Line 11

Maybe there's some sort of conflict between different jquery definitions? (or something)

$(document).ready(function() {
  //initiate the shadowbox player
//  Shadowbox.init({
//    players:  ['html', 'iframe']
//  });
}); 

jQuery(function(){
  jQuery('input#search')
    .data('timeout', null)
    .keyup(function(){
      jQuery(this).data('timeout', setTimeout(function(){
          var mytext = jQuery('input#search').val();
          submitQuizForm();
          jQuery('input#search').next().html(mytext);
        }, 2000)
     )
     .keydown(function(){
       clearTimeout(jQuery(this).data('timeout'));
     });
    });
});

function submitQuizForm(){
  form = jQuery("#searchQuizzes");
  jQuery.ajax({
    async:true, 
    data:jQuery.param(form.serializeArray()), 
    dataType:'script', 
    type:'get', 
    url:'/millionaire/millionaire_quizzes',
    success: function(msg){ 
     // $("#chooseQuizMainTable").trigger("update"); 
    }
  }); 
  return true;
}
+4  A: 

Sorry i haven't tested this and it's a bit off the top of my head, but something along these lines should hopefully do the trick. Change the 2000 to however many milliseconds you need between server posts

<input type="text" id="mytextbox" style="border: 1px solid" />
<span></span>

<script language="javascript" type="text/javascript">
    jQuery(function(){
      jQuery('#mytextbox')
        .data('timeout', null)
        .keyup(function(){
            clearTimeout(jQuery(this).data('timeout'));
            jQuery(this).data('timeout', setTimeout(submitQuizForm, 2000));
        });
    });
</script>
danrichardson
inside the setTimeout function you MIGHT be able to change jQuery('#myelement') to jQuery(this)
danrichardson
Thanks dan - it's falling over at the first .data('timeout', null), saying it's not a function. Do i have to do something else before i can call .data? I'm calling it on a text field in this instance.
Max Williams
Max, have you made sure you have included the jQuery library and changed #myelement to your own element selector? I have just given it a quick test and it's working spot on :) Dan
danrichardson
Also you will want to make sure you have it in a jQuery load function. My orignal answer has been updated with the full code. Dan
danrichardson
ah, that's working great now, thanks. I was calling your previous entry from inside another function, before. I've not encountered jquery load functions before, like i say i'm a bit of a js novice. thanks again! max
Max Williams
Actually dan, i spoke too soon. I think the logic is a bit messed up. I replaced the comment (// Run some more logic - ajax post/get?) with a call to another function which submits the form remotely. And now, when typing 'mathematics', fairly quickly, into the empty search box, i see 12 different calls. Looking in my server log i can see the calls, which have a sequence of terms from the search box - "mathema", "mathemat", "mathemat", "mathematic", "mathematic", "mathematics", "mathematics", "mathematics", "mathematics", "mathematics", "mathematics", "mathematics"
Max Williams
Can you update your question with your current code? Just paste it into the textarea (in your question), select the code and hit the code button to auto format it all. :) Dan
danrichardson
Dan - updated post, thanks
Max Williams
Hmm, i think you might be able to remove the jQuery-latest.js, as you are probably including the jQuery library elsewhere on the page? If it's literally just including the library again you can remove it. Though in your submitQuizForm function i would rename "form" to something like "quizform", as form might be picked up as a reserved word in javascript.
danrichardson
Hi Dan. Removed that call to jquery-latest and replaced the form varname with quizForm but the essential problem remains of it making 12 calls when i type in 'mathematics' into the empty search box. I guess that the timeout isn't being reset by the keydowns for some reason?
Max Williams
Doh! I have sorted it for you :)All you need to do is remove the ".keydown(function(){})" function, and place the "clearTimeout(jQuery(this).data('timeout'));" inside of the keyup function as the first thing, i will edit my post :) Dan
danrichardson
Thanks dan. I actually ended up rewriting it to do just that and it seems to work pretty well. I factored it into a method - see my answer below. cheers, max
Max Williams
A: 

As an update, i ended up with this which seems to work well:

function afterDelayedKeyup(selector, action, delay){
  jQuery(selector).keyup(function(){
    if(typeof(window['inputTimeout']) != "undefined"){
      clearTimeout(inputTimeout);
    }  
    inputTimeout = setTimeout(action, delay);
  });
}

I then call this from the page in question's document.ready block with

  afterDelayedKeyup('input#search',"submitQuizForm()",500)

What would be nice would be to make a new jquery event which uses this logic, eg .delayedKeyup to go alongside .keyup, so i could just say something like this for an individual page's document.ready block.

  jQuery('input#search').delayedKeyup(function(){
    submitQuizForm();
  });

But, i don't know how to customise jquery in this way. That's a nice homework task though.

Max Williams