786 votes

Comment retarder le gestionnaire .keyup() jusqu'à ce que l'utilisateur arrête de taper ?

J'ai un champ de recherche. Actuellement, il recherche chaque combinaison de touches. Donc si quelqu'un tape "Windows", il va faire une recherche avec AJAX pour chaque combinaison de touches : "W", "Wi", "Win", "Wind", "Windo", "Window", "Windows".

Je veux avoir un délai, de sorte que la recherche ne soit effectuée que lorsque l'utilisateur cesse de taper pendant 200 ms.

Il n'y a pas d'option pour cela dans le keyup et j'ai essayé setTimeout mais ça n'a pas marché.

Comment puis-je faire ça ?

4 votes

2 votes

Si je pouvais, je fermerais ceci comme un doublon.

11 votes

Je ne vois pas l'intérêt d'avoir des doublons, tant que les réponses données et acceptées sont correctes. L'enrichissement de la base de données des questions doit être une bonne chose et un objectif à atteindre.

1334voto

CMS Points 315406

J'utilise cette petite fonction dans le même but, en exécutant une fonction après que l'utilisateur a cessé de taper pendant une durée déterminée ou dans des événements qui se déclenchent à un rythme élevé, tels que resize :

function delay(callback, ms) {
  var timer = 0;
  return function() {
    var context = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      callback.apply(context, args);
    }, ms || 0);
  };
}

// Example usage:

$('#input').keyup(delay(function (e) {
  console.log('Time elapsed!', this.value);
}, 500));

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label for="input">Try it:
<input id="input" type="text" placeholder="Type something here..."/>
</label>

Comment cela fonctionne :

El delay renvoie une fonction enveloppée qui gère en interne une minuterie individuelle. À chaque exécution, la minuterie est redémarrée avec le délai fourni, si plusieurs exécutions ont lieu avant que ce délai ne soit écoulé, la minuterie est simplement réinitialisée et recommence.

Lorsque la minuterie se termine enfin, la fonction de rappel est exécutée, en passant le contexte et les arguments d'origine (dans cet exemple, l'objet événement de jQuery, et l'élément DOM en tant que this ).

MISE À JOUR 2019-05-16

J'ai réimplémenté la fonction en utilisant les fonctionnalités ES5 et ES6 pour les environnements modernes :

function delay(fn, ms) {
  let timer = 0
  return function(...args) {
    clearTimeout(timer)
    timer = setTimeout(fn.bind(this, ...args), ms || 0)
  }
}

La mise en œuvre est couverte par un série de tests .

Pour quelque chose de plus sophistiqué, jetez un coup d'œil à jQuery Typewatch plugin.

68 votes

Une autre alternative : github.com/bgrins/bindWithDelay/blob/master/bindWithDelay.js . Il fonctionne à peu près de la même façon que vous l'avez décrit, je me suis juste retrouvé à utiliser ce modèle très souvent et je l'ai implémenté en tant que plugin jQuery pour rendre la syntaxe plus simple. Voici une page de démonstration : briangrinstead.com/files/bindWithDelay

3 votes

J'ai initialement codé en dur la quantité de lettres tapées, cette approche est douce comme de la mélasse (sans soufre)

2 votes

Lorsque je l'utilise avec un $.post(), il envoie tout ce qui a été tapé en même temps, mais il l'envoie autant de fois que j'ai eu de touches. Existe-t-il un moyen d'envoyer UNIQUEMENT lorsque le délai d'attente est écoulé ?

70voto

RHicke Points 1016

Si vous souhaitez effectuer une recherche après que le type est terminé, utilisez une variable globale pour contenir le délai d'attente renvoyé par votre fichier setTimout et l'annuler avec un clearTimeout s'il n'est pas encore arrivé, de sorte qu'il ne déclenche pas le délai d'attente sauf sur le dernier keyup événement

var globalTimeout = null;  
$('#id').keyup(function(){
  if(globalTimeout != null) clearTimeout(globalTimeout);  
  globalTimeout =setTimeout(SearchFunc,200);  
}   
function SearchFunc(){  
  globalTimeout = null;  
  //ajax code
}

Ou avec une fonction anonyme :

var globalTimeout = null;  
$('#id').keyup(function() {
  if (globalTimeout != null) {
    clearTimeout(globalTimeout);
  }
  globalTimeout = setTimeout(function() {
    globalTimeout = null;  

    //ajax code

  }, 200);  
}

33voto

meleyal Points 7367

Vous pouvez également consulter underscore.js qui fournit des méthodes utilitaires telles que rebondissement :

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

0 votes

La même chose est également disponible en Lodash. lodash.com/docs/#debounce

15voto

Gaten Points 61

Sur la base de la réponse du CMS, j'ai réalisé ce :

Mettez le code ci-dessous après include jQuery :

/*
 * delayKeyup
 * http://code.azerti.net/javascript/jquery/delaykeyup.htm
 * Inspired by CMS in this post : http://stackoverflow.com/questions/1909441/jquery-keyup-delay
 * Written by Gaten
 * Exemple : $("#input").delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
 */
(function ($) {
    $.fn.delayKeyup = function(callback, ms){
        var timer = 0;
        $(this).keyup(function(){                   
            clearTimeout (timer);
            timer = setTimeout(callback, ms);
        });
        return $(this);
    };
})(jQuery);

Et utilisez simplement comme ceci :

$('#input').delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);

Attention : la variable $(this) dans la fonction passée en paramètre ne correspond pas à l'entrée

6voto

Sagar Gala Points 473

Cela a fonctionné pour moi où j'ai retardé l'opération de logique de recherche et fait une vérification si la valeur est la même que celle entrée dans le champ de texte. Si la valeur est la même, je continue et j'effectue l'opération pour les données liées à la valeur de recherche.

$('#searchText').on('keyup',function () {
    var searchValue = $(this).val();
    setTimeout(function(){
        if(searchValue == $('#searchText').val() && searchValue != null && searchValue != "") {
           // logic to fetch data based on searchValue
        }
        else if(searchValue == ''){
           // logic to load all the data
        }
    },300);
});

0 votes

Ne fonctionne pas comme prévu - le nombre de recherches est le même, mais retardé de 300 ms - vous devez utiliser la fonction clearTimeout() à chaque frappe, avant d'exécuter la fonction setTimeout().

0 votes

Vous n'avez pas besoin d'utiliser le clearTimeout dans ce cas. La condition searchValue == $('#searchText').val() dans setTimeout garantira que la valeur est la même que celle d'il y a 300 ms. Dites-moi si cela a du sens. Merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X