Can I delay the keyup event for jquery?

2019-04-20 06:52发布

问题:

I'm using the rottentomatoes movie API in conjunction with twitter's typeahead plugin using bootstrap 2.0. I've been able to integerate the API but the issue I'm having is that after every keyup event the API gets called. This is all fine and dandy but I would rather make the call after a small pause allowing the user to type in several characters first.

Here is my current code that calls the API after a keyup event:

    var autocomplete = $('#searchinput').typeahead()
    .on('keyup', function(ev){

        ev.stopPropagation();
        ev.preventDefault();

        //filter out up/down, tab, enter, and escape keys
        if( $.inArray(ev.keyCode,[40,38,9,13,27]) === -1 ){

            var self = $(this);

            //set typeahead source to empty
            self.data('typeahead').source = [];

            //active used so we aren't triggering duplicate keyup events
            if( !self.data('active') && self.val().length > 0){

                self.data('active', true);

                //Do data request. Insert your own API logic here.
                $.getJSON("http://api.rottentomatoes.com/api/public/v1.0/movies.json?callback=?&apikey=MY_API_KEY&page_limit=5",{
                    q: encodeURI($(this).val())
                }, function(data) {

                    //set this to true when your callback executes
                    self.data('active',true);

                    //Filter out your own parameters. Populate them into an array, since this is what typeahead's source requires
                    var arr = [],
                        i=0;

                    var movies = data.movies;

                     $.each(movies, function(index, movie) {
                        arr[i] = movie.title
                        i++;
                     });

                    //set your results into the typehead's source 
                    self.data('typeahead').source = arr;

                    //trigger keyup on the typeahead to make it search
                    self.trigger('keyup');

                    //All done, set to false to prepare for the next remote query.
                    self.data('active', false);

                });

            }
        }
    });

Is it possible to set a small delay and avoid calling the API after every keyup?

回答1:

it can be easily done like this:

var autocomplete = $('#searchinput').typeahead().on('keyup', delayRequest);

function dataRequest() {
    // api request here
}

function delayRequest(ev) {
    if(delayRequest.timeout) {
        clearTimeout(delayRequest.timeout);
    }

    var target = this;

    delayRequest.timeout = setTimeout(function() {
        dataRequest.call(target, ev);
    }, 200); // 200ms delay
}


回答2:

In general, this can be achieved with setTimeout and clearTimeout methods:

var timer;

$('#textbox').keyup(function() {
    if (timer) {
        clearTimeout(timer);
    }
    timer = setTimeout('alert("Something cool happens here....");', 500);
});

setTimeout will execute the provided javascript after the specified interval in milliseconds passes. clearTimeout will cancel this execution.

I've also prepared jsFiddle demo showing the code snippet in action.

References:

  • Javascript timing methods


回答3:

For people working with v0.11 of typeahead.js and using Bloodhound to fetch remote suggestions, you can use the rateLimitWait option to throttle requests:

var search = new Bloodhound({
  datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
  queryTokenizer: Bloodhound.tokenizers.whitespace,
  remote: {
    url: '/search?q=%QUERY',
    rateLimitWait: 500
  }
});


回答4:

Not sure what version Bootstrap 2.0 uses for typeahead, but v0.9.3 has a minLength option that's hidden under the hood, but not documented.

$('#people').typeahead({
  name: 'people',
  prefetch: './names.json',
  minLength: 3
});

As found from this blog post: http://tosbourn.com/2013/08/javascript/setting-a-minimum-length-for-your-search-in-typeahead-js/



回答5:

Rather than a delay, if you just want to allow the user to enter a few characters before the ajax $.getJSON request, you could amend the if statement so that the user has to enter a minimum number of characters, for example 3, before you request the data:

if( !self.data('active') && self.val().length >=3){