Comment retarder l'.keyup () handler jusqu'à ce que l'utilisateur cesse de taper?
j'ai un champ de recherche. En ce moment, il recherche chaque keyup. Donc, si quelqu'un tape "Windows", il fera une recherche avec AJAX pour chaque keyup: "W", "Wi", "Gagner", "Vent", "Windo", "Fenêtre", "Windows".
je veux avoir un délai, donc il ne recherche que lorsque l'utilisateur arrête de taper pendant 200 ms.
il n'y a pas d'option pour cela dans la fonction keyup
, et j'ai essayé setTimeout
, mais ça n'a pas marché.
Comment peut - Je le faire?
24 réponses
j'utilise cette fonction dans le même but, en exécutant une fonction après que l'Utilisateur a cessé de taper pendant un certain temps:
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
Utilisation:
$('input').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000 );
});
Pour quelque chose de plus sophistiqué, donner un coup d'oeil à la jQuery Typewatch plugin.
si vous voulez rechercher après que le type est fait utiliser une variable globale pour tenir le temps d'arrêt retourné de votre setTimout
appel et l'annuler avec un clearTimeout
si elle n'a pas encore happend de sorte qu'il ne sera pas tirer le temps d'arrêt 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);
}
une autre légère amélioration sur la réponse DE CMS. Pour permettre facilement des délais séparés, vous pouvez utiliser ce qui suit:
function makeDelay(ms) {
var timer = 0;
return function(callback){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
};
Si vous voulez réutiliser le même délai, il suffit de faire
var delay = makeDelay(250);
$(selector1).on('keyup', function() {delay(someCallback);});
$(selector2).on('keyup', function() {delay(someCallback);});
si vous voulez des délais séparés, vous pouvez le faire
$(selector1).on('keyup', function() {makeDelay(250)(someCallback);});
$(selector2).on('keyup', function() {makeDelay(250)(someCallback);});
vous pouvez aussi regarder souligné.js , qui fournit des méthodes d'utilité comme debounce :
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
basé sur la réponse DE CMS, j'ai fait ceci:
mettez le code ci-dessous après inclure jQuery:
/*
* delayKeyup
* http://code.azerti.net/javascript/jquery/delaykeyup.htm
* Inspired by CMS in this post : /q/how-to-delay-the-keyup-handler-until-the-user-stops-typing-25671/"#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 $(ceci) de la fonction passée en paramètre ne correspond pas à l'entrée
Retard Multi Fonction des Appels à l'aide des Étiquettes
C'est la solution avec laquelle je travaille. il retardera l'exécution sur N'importe quelle fonction que vous voulez . Ce peut être la requête de recherche keydown, peut-être le clic rapide sur les boutons Précédent ou suivant ( qui enverrait autrement la requête multiple si cliqué rapidement en continu , et ne pas être utilisé après tout). Cela utilise un objet global qui stocke chaque temps d'exécution, et le compare avec le plus la demande actuelle.
ainsi le résultat est que seul ce dernier clic / action sera effectivement appelé, parce que ces requêtes sont stockées dans une file d'attente, qu'après le x millisecondes est appelé si aucune autre requête avec la même étiquette n'existe dans la file d'attente!
function delay_method(label,callback,time){
if(typeof window.delayed_methods=="undefined"){window.delayed_methods={};}
delayed_methods[label]=Date.now();
var t=delayed_methods[label];
setTimeout(function(){ if(delayed_methods[label]!=t){return;}else{ callback();}}, time||500);
}
vous pouvez définir votre propre Délai ( son optionnel, par défaut à 500ms). Et envoyer vos arguments de fonction dans une"manière de fermeture".
Par exemple, si vous voulez appeler la fonction bellow:
function send_ajax(id){console.log(id);}
pour empêcher les requêtes send_ajax multiples, vous les retardez en utilisant:
delay_method( "check date", function(){ send_ajax(2); } ,600);
toute demande qui utilise l'étiquette "date de vérification" ne sera déclenchée que si aucune autre demande n'est faite dans le délai de 600 millisecondes. Cet argument est optionnel
Label Independence (appelant la même fonction cible) mais exécuter les deux:
delay_method("check date parallel", function(){send_ajax(2);});
delay_method("check date", function(){send_ajax(2);});
a pour résultat d'appeler la même fonction mais de les retarder indépendamment à cause de leurs étiquettes étant différentes
cette fonction étend un peu la fonction de la réponse de Gaten afin de récupérer l'élément:
$.fn.delayKeyup = function(callback, ms){
var timer = 0;
var el = $(this);
$(this).keyup(function(){
clearTimeout (timer);
timer = setTimeout(function(){
callback(el)
}, ms);
});
return $(this);
};
$('#input').delayKeyup(function(el){
//alert(el.val());
// Here I need the input element (value for ajax call) for further process
},1000);
je suis surpris que personne ne mentionne le problème avec les entrées multiples dans le très joli snipped DE CMS.
fondamentalement, vous devriez définir la variable de retard individuellement pour chaque entrée. Sinon, si sb met du texte à la première entrée et passe rapidement à une autre entrée et commence à taper, le premier ne sera pas appelé !
voir le code ci-dessous je suis venu avec basé sur d'autres réponses:
(function($) {
/**
* KeyUp with delay event setup
*
* @link http://stackoverflow.com/questions/1909441/jquery-keyup-delay#answer-12581187
* @param function callback
* @param int ms
*/
$.fn.delayKeyup = function(callback, ms){
$(this).keyup(function( event ){
var srcEl = event.currentTarget;
if( srcEl.delayTimer )
clearTimeout (srcEl.delayTimer );
srcEl.delayTimer = setTimeout(function(){ callback( $(srcEl) ); }, ms);
});
return $(this);
};
})(jQuery);
Cette solution permet de conserver la référence setTimeout dans la variable delayTimer de l'input. Il transmet également la référence de l'élément au callback comme suggéré par fazzyx.
testé en IE6, 8 (comp-7), 8 et Opera 12.11.
cela a fonctionné pour moi où je retarde l'opération logique de recherche et vérifie si la valeur est la même que celle entrée dans le champ de texte. Si la valeur est la même, alors je vais de l'avant et effectuer 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);
});
fonction de délai pour appeler sur chaque keyup. jQuery 1.7.1 ou plus requis
jQuery.fn.keyupDelay = function( cb, delay ){
if(delay == null){
delay = 400;
}
var timer = 0;
return $(this).on('keyup',function(){
clearTimeout(timer);
timer = setTimeout( cb , delay );
});
}
Utilisation: $('#searchBox').keyupDelay( cb );
si quelqu'un veut retarder la même fonction, et sans variable externe, il peut utiliser le script suivant:
function MyFunction() {
//Delaying the function execute
if (this.timer) {
window.clearTimeout(this.timer);
}
this.timer = window.setTimeout(function() {
//Execute the function code here...
}, 500);
}
approche Super simple, conçue pour exécuter une fonction après qu'un utilisateur a fini de taper dans un champ de texte...
<script type="text/javascript">
$(document).ready(function(e) {
var timeout;
var delay = 2000; // 2 seconds
$('.text-input').keyup(function(e) {
console.log("User started typing!");
if(timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
myFunction();
}, delay);
});
function myFunction() {
console.log("Executing function for user!");
}
});
</script>
<textarea name="text-input" class="text-input"></textarea>
Utiliser
mytimeout = setTimeout( expression, timeout );
où expression est le script à exécuter et timeout est le temps d'attente en millisecondes avant qu'il ne démarre - cela ne hante pas le script, mais retarde simplement l'exécution de cette partie jusqu'à ce que le timeout soit terminé.
clearTimeout(mytimeout);
réinitialiser/effacer le délai d'attente afin de ne pas exécuter le script dans l'expression (comme un annuler), tant qu'il n'a pas encore été exécuté.
C'est une solution le long de la lignes de la CMS, mais résout quelques problèmes importants pour moi:
- prend en charge plusieurs entrées, les délais peuvent être exécutés simultanément.
- ignore les événements clés qui n'ont pas changé la valeur (comme Ctrl, Alt+Tab).
- résout une condition de course (lorsque le callback est exécuté et que la valeur a déjà été modifiée).
var delay = (function() {
var timer = {}
, values = {}
return function(el) {
var id = el.form.id + '.' + el.name
return {
enqueue: function(ms, cb) {
if (values[id] == el.value) return
if (!el.value) return
var original = values[id] = el.value
clearTimeout(timer[id])
timer[id] = setTimeout(function() {
if (original != el.value) return // solves race condition
cb.apply(el)
}, ms)
}
}
}
}())
Utilisation:
signup.key.addEventListener('keyup', function() {
delay(this).enqueue(300, function() {
console.log(this.value)
})
})
le code est écrit dans un style que j'aime, vous pouvez avoir besoin d'ajouter un tas de point-virgule.
Choses à garder à l'esprit:
- un id unique est généré en fonction de l'id du formulaire et du nom d'entrée, de sorte qu'ils doivent être définis et uniques, ou vous pouvez l'ajuster à votre situation.
- delay retourne un objet facile à étendre pour vos propres besoins.
- l'élément original utilisé pour le delay est lié au callback, donc
this
fonctionne comme prévu (comme dans l'exemple).
La valeur vide - est ignorée dans la seconde validation.
- attention de enqueue , il attend de millisecondes d'abord, je préfère ça, mais vous pouvez choisir de changer les paramètres pour correspondre à
setTimeout
.
la solution que j'utilise ajoute un autre niveau de complexité, permettant vous pour annuler l'exécution, par exemple, mais c'est une bonne base pour construire sur.
basé sur la réponse DE CMS, il ignore tout simplement les événements clés qui ne changent pas de valeur.
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
var duplicateFilter=(function(){
var lastContent;
return function(content,callback){
content=$.trim(content);
if(content!=lastContent){
callback(content);
}
lastContent=content;
};
})();
$("#some-input").on("keyup",function(ev){
var self=this;
delay(function(){
duplicateFilter($(self).val(),function(c){
//do sth...
console.log(c);
});
}, 1000 );
})
S'appuyant sur la réponse DE CMS voici la nouvelle méthode de retard qui préserve "ceci" dans son usage:
var delay = (function(){
var timer = 0;
return function(callback, ms, that){
clearTimeout (timer);
timer = setTimeout(callback.bind(that), ms);
};
})();
Utilisation:
$('input').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, this);
});
utilisez le bindWithDelay jQuery plugin:
element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)
var globalTimeout = null;
$('#search').keyup(function(){
if(globalTimeout != null) clearTimeout(globalTimeout);
globalTimeout =setTimeout(SearchFunc,200);
});
function SearchFunc(){
globalTimeout = null;
console.log('Search: '+$('#search').val());
//ajax code
};
Voici une suggestion que j'ai écrite qui s'occupe de plusieurs entrées dans votre forme.
cette fonction reçoit L'objet du champ d'entrée, mis dans votre code
function fieldKeyup(obj){
// what you want this to do
} // fieldKeyup
il s'agit de la fonction delayCall réelle, prend soin de plusieurs champs d'entrée
function delayCall(obj,ms,fn){
return $(obj).each(function(){
if ( typeof this.timer == 'undefined' ) {
// Define an array to keep track of all fields needed delays
// This is in order to make this a multiple delay handling
function
this.timer = new Array();
}
var obj = this;
if (this.timer[obj.id]){
clearTimeout(this.timer[obj.id]);
delete(this.timer[obj.id]);
}
this.timer[obj.id] = setTimeout(function(){
fn(obj);}, ms);
});
}; // delayCall
Utilisation:
$("#username").on("keyup",function(){
delayCall($(this),500,fieldKeyup);
});
combinant CMS answer avec Miguel fournit une solution robuste permettant des retards simultanés.
var delay = (function(){
var timers = {};
return function (callback, ms, label) {
label = label || 'defaultTimer';
clearTimeout(timers[label] || 0);
timers[label] = setTimeout(callback, ms);
};
})();
lorsque vous devez retarder différentes actions indépendamment, utilisez le troisième argument.
$('input.group1').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, 'firstAction');
});
$('input.group2').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, '2ndAction');
});
regardez le autocomplete plugin. Je sais que cela vous permet de spécifier un délai ou un nombre minimum de caractères. Même si vous ne finissez pas par utiliser le plugin, regarder le code vous donnera quelques idées sur la façon de l'implémenter vous-même.
Eh bien, j'ai aussi fait un morceau de code pour limite haute fréquence demande ajax cause par Keyup / Keydown. Regardez ça:
https://github.com/raincious/jQueue
faites votre requête comme ceci:
var q = new jQueue(function(type, name, callback) {
return $.post("/api/account/user_existed/", {Method: type, Value: name}).done(callback);
}, 'Flush', 1500); // Make sure use Flush mode.
et lient l'événement comme ceci:
$('#field-username').keyup(function() {
q.run('Username', this.val(), function() { /* calling back */ });
});
a vu cela aujourd'hui un peu tard, mais je veux juste mettre ceci ici au cas où quelqu'un d'autre aurait besoin. il suffit de séparer la fonction pour la rendre réutilisable. le code ci-dessous attendra 1/2 seconde après avoir tapé stop.
var timeOutVar
$(selector).on('keyup', function() {
clearTimeout(timeOutVar);
timeOutVar= setTimeout(function(){ console.log("Hello"); }, 500);
});
de ES6 , on peut utiliser la syntaxe de fonction de flèche aussi bien.
dans cet exemple, le code retarde keyup
événement pour 400ms après que les utilisateurs aient fini de taper avant d'appeler searchFunc
faire une requête de requête.
const searchbar = document.getElementById('searchBar');
const searchFunc = // any function
// wait ms (milliseconds) after user stops typing to execute func
const delayKeyUp = (() => {
let timer = null;
const delay = (func, ms) => {
timer ? clearTimeout(timer): null
timer = setTimeout(func, ms)
}
return delay
})();
searchbar.addEventListener('keyup', (e) => {
const query = e.target.value;
delayKeyUp(() => {searchFunc(query)}, 400);
})