Exécuter la fonction javascript lorsque l'Utilisateur termine de taper au lieu de sur la touche up?

Je veux déclencher une requête ajax lorsque l'utilisateur a terminé de taper dans une zone de texte. Je ne veux pas qu'il exécute la fonction à chaque fois que l'utilisateur tape une lettre car cela entraînerait beaucoup de requêtes ajax, mais je ne veux pas non plus qu'ils aient à appuyer sur le bouton Entrée.

Existe-t-il un moyen pour que je puisse détecter quand l'Utilisateur a fini de taper et ensuite faire la requête ajax?

Utiliser jQuery ici! Dave

362
demandé sur Macmee 2010-11-19 01:13:04

22 réponses

Donc, je vais deviner que finir de taper signifie que vous arrêtez juste pendant un moment, disons 5 secondes. Donc, dans cet esprit, permet de démarrer une minuterie lorsque l'utilisateur libère une clé et l'effacer quand ils appuient sur un. J'ai décidé que l'entrée en question sera #myInput.

Faire quelques hypothèses...

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example
var $input = $('#myInput');

//on keyup, start the countdown
$input.on('keyup', function () {
  clearTimeout(typingTimer);
  typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$input.on('keydown', function () {
  clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
527
répondu Surreal Dreams 2015-07-16 20:32:41

La réponse choisie ci-dessus ne fonctionne pas.

Parce que typingTimer est occasionnellement réglé plusieurs fois (keyup pressé deux fois avant que keydown ne soit déclenché pour les typeurs rapides, etc.), alors il n'est pas évident de bien.

La solution ci-dessous résout ce problème et appellera X secondes après avoir terminé comme L'OP demandé. Il ne nécessite plus non plus la fonction KeyDown redondante. J'ai également ajouté une vérification afin que votre appel de fonction ne se produise pas si votre entrée est vide.

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms (5 seconds)

//on keyup, start the countdown
$('#myInput').keyup(function(){
    clearTimeout(typingTimer);
    if ($('#myInput').val()) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

Et le même code dans la solution JavaScript vanille:

//setup before functions
let typingTimer;                //timer identifier
let doneTypingInterval = 5000;  //time in ms (5 seconds)
let myInput = document.getElementById('myInput');

//on keyup, start the countdown
myInput.addEventListener('keyup', () => {
    clearTimeout(typingTimer);
    if (myInput.value) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

Cette solution utilise ES6 mais ce n'est pas nécessaire ici. Remplacez simplement let par var et la fonction Flèche par une fonction régulière.

303
répondu going 2018-08-17 20:12:17

C'est juste une ligne avec trait de soulignement.js fonction anti-rebond:

$('#my-input-box').keyup(_.debounce(doSomething , 500));

Cela dit essentiellement doSomething 500 millisecondes après avoir arrêté de taper.

Pour plus d'Informations: http://underscorejs.org/#debounce

67
répondu bit2pixel 2016-04-13 12:53:48

Oui, vous pouvez définir un délai d'attente de 2 secondes sur chaque touche jusqu'à l'événement qui déclenche une requête ajax. Vous pouvez également stocker la méthode XHR et l'abandonner lors des événements de presse de touche suivants afin d'économiser encore plus la bande passante. Voici quelque chose que j'ai écrit pour un script de saisie semi-automatique.

var timer;
var x;

$(".some-input").keyup(function () {
    if (x) { x.abort() } // If there is an existing XHR, abort it.
    clearTimeout(timer); // Clear the timer so we don't end up with dupes.
    timer = setTimeout(function() { // assign timer a new timeout 
        x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
    }, 2000); // 2000ms delay, tweak for faster/slower
});

J'espère que cela aide,

Marko

39
répondu Marko 2010-11-18 22:19:53
var timer;
var timeout = 1000;

$('#in').keyup(function(){
    clearTimeout(timer);
    if ($('#in').val) {
        timer = setTimeout(function(){
            //do stuff here e.g ajax call etc....
             var v = $("#in").val();
             $("#out").html(v);
        }, timeout);
    }
});

Exemple Complet ici: http://jsfiddle.net/ZYXp4/8/

16
répondu azzy81 2012-08-14 13:11:25

J'aime la réponse de surreal Dream mais j'ai trouvé que ma fonction " doneTyping "se déclencherait pour chaque pression de touche, c'est-à-dire si vous tapez" Hello " très rapidement; au lieu de tirer une seule fois lorsque vous arrêtez de taper, la fonction se déclencherait 5 fois.

Le problème était que la fonction javascript setTimeout ne semble pas écraser ou tuer les anciens délais d'attente qui ont été définis, mais si vous le faites vous-même, cela fonctionne! Donc, je viens d'ajouter un appel clearTimeout juste avant setTimeout si le typingTimer est définir. Voir ci-dessous:

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example

//on keyup, start the countdown
$('#myInput').on("keyup", function(){
    if (typingTimer) clearTimeout(typingTimer);                 // Clear if already set     
    typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$('#myInput').on("keydown", function(){
    clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

N.B. j'aurais aimé juste ajouter ceci comme commentaire à la réponse de surreal Dream mais je suis un nouvel utilisateur et je n'ai pas assez de réputation. Pardon!

9
répondu Liam Flanagan 2014-01-15 11:07:54

Modifier la réponse acceptée pour gérer des cas supplémentaires tels que paste:

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 2000;  //time in ms, 2 second for example
var $input = $('#myInput');

// updated events 
$input.on('input propertychange paste', function () {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(doneTyping, doneTypingInterval);      
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
8
répondu Jecoms 2016-08-30 18:45:21

Eh bien, à proprement parler non, car l'ordinateur ne peut pas deviner quand l'Utilisateur a fini de taper. Vous pouvez bien sûr tirer une minuterie sur la touche, et le réinitialiser sur chaque touche suivante. Si la minuterie expire, l'utilisateur n'a pas tapé pour la durée de la minuterie-vous pouvez appeler cela "fini de taper".

Si vous vous attendez à ce que les utilisateurs fassent des pauses en tapant, il n'y a aucun moyen de savoir quand ils ont terminé.

(à moins bien sûr que vous puissiez dire à partir des données quand elles sont faites)

4
répondu sleske 2010-11-18 22:16:03

Je ne pense pas que l'événement keyDown soit nécessaire dans ce cas (veuillez me dire pourquoi si je me trompe). Dans mon script (non-jquery), une solution similaire ressemble à ceci:

var _timer, _timeOut = 2000; 



function _onKeyUp(e) {
    clearTimeout(_timer);
    if (e.keyCode == 13) {      // close on ENTER key
        _onCloseClick();
    } else {                    // send xhr requests
        _timer = window.setTimeout(function() {
            _onInputChange();
        }, _timeOut)
    }

}

C'est ma première réponse sur le débordement de pile, donc j'espère que cela aidera quelqu'un, un jour:)

4
répondu Rafal Pastuszak 2011-10-05 19:44:42

SOLUTION:

J'implémentais la recherche sur ma liste et j'ai besoin qu'elle soit basée sur ajax. Cela signifie que sur chaque changement de clé les résultats recherchés doivent être mis à jour et affichés. Ce travail se traduit par tant d'appels ajax envoyés au serveur, ce qui n'est pas une bonne chose. Après quelques travaux, j'ai fait une approche du serveur ping lorsque le client arrête de taper.

La solution a fonctionné pour moi est:

$(document).ready(function() {

$('#yourtextfield').keyup(function() {
s = $('#yourtextfield').val();
setTimeout(function() { 
        if($('#yourtextfield').val() == s){ // Check the value searched is the latest one or not. This will help in making the ajax call work when client stops writing.
            $.ajax({
                type: "POST",
                url: "yoururl",
                data: 'search=' + s,
                cache: false,
                beforeSend: function() {
                   // loading image
                },
                success: function(data) {
                    // Your response will come here
                }
            })
        }
    }, 1000); // 1 sec delay to check.

    }); // End of  keyup function

    }); // End of document.ready

Vous avez remarqué qu'il n'est pas nécessaire d'utiliser une minuterie lors de la mise en œuvre ce.

Je suis sûr que cela aidera les autres.

Ata

2
répondu Ata ul Mustafa 2013-08-28 10:03:36

J'ai l'impression que la solution est un peu plus simple avec l'événement input:

var typingTimer;
var doneTypingInterval = 500;

$("#myInput").on("input", function () {
    window.clearTimeout(typingTimer);
    typingTimer = window.setTimeout(doneTyping, doneTypingInterval);
});

function doneTyping () {
    // code here
}
2
répondu Adrien Brunelat 2016-04-26 13:35:21

Les deux premières réponses 2 ne fonctionnent pas pour moi. Alors, voici ma solution:

var timeout = null;

$('#myInput').keyup(function() {
    clearTimeout(timeout);

    timeout = setTimeout(function() {
        //do stuff here
    }, 500);
});
2
répondu YSFKBDY 2018-02-08 07:11:14

Vous pouvez utiliser l'événement onblur pour détecter quand la zone de texte perd le focus: https://developer.mozilla.org/en/DOM/element.onblur

Ce n'est pas la même chose que "arrête de taper", si vous vous souciez du cas où l'utilisateur tape un tas de choses et se trouve là avec la zone de texte toujours concentrée.

Pour cela, je suggère de lier un setTimeout à l'événement onclick, et en supposant qu'après x temps sans frappe, l'Utilisateur a cessé de taper.

1
répondu Mike Ruhlin 2010-11-18 22:17:47

C'est le code JS simple que j'ai écrit:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-br" lang="pt-br">
<head><title>Submit after typing finished</title>
<script language="javascript" type="text/javascript">
function DelayedSubmission() {
    var date = new Date();
    initial_time = date.getTime();
    if (typeof setInverval_Variable == 'undefined') {
            setInverval_Variable = setInterval(DelayedSubmission_Check, 50);
    } 
}
function DelayedSubmission_Check() {
    var date = new Date();
    check_time = date.getTime();
    var limit_ms=check_time-initial_time;
    if (limit_ms > 800) { //Change value in milliseconds
        alert("insert your function"); //Insert your function
        clearInterval(setInverval_Variable);
        delete setInverval_Variable;
    }
}

</script>
</head>
<body>

<input type="search" onkeyup="DelayedSubmission()" id="field_id" style="WIDTH: 100px; HEIGHT: 25px;" />

</body>
</html>
1
répondu Alfredo Lingoist Jr. 2015-02-22 01:45:31

Une fois que vous avez détecté le focus sur la zone de texte, sur key up, effectuez une vérification du délai d'attente et réinitialisez-le chaque fois qu'il est déclenché.

Lorsque le délai d'attente est terminé, faites votre requête ajax.

0
répondu ocodo 2010-11-18 22:16:42

Si vous recherchez une longueur spécifique (comme un champ de code postal):

$("input").live("keyup", function( event ){
if(this.value.length == this.getAttribute('maxlength')) {
        //make ajax request here after.
    }
  });
0
répondu Jason 2012-08-09 22:15:48

Je ne sais pas si mes besoins sont juste un peu bizarres, mais j'avais besoin de quelque chose de similaire à ceci et c'est ce que j'ai fini par utiliser:

$('input.update').bind('sync', function() {
    clearTimeout($(this).data('timer'));            
    $.post($(this).attr('data-url'), {value: $(this).val()}, function(x) {
        if(x.success != true) {
            triggerError(x.message);    
        }
    }, 'json');
}).keyup(function() {
    clearTimeout($(this).data('timer'));
    var val = $.trim($(this).val());
    if(val) {
        var $this = $(this);
        var timer = setTimeout(function() {
            $this.trigger('sync');
        }, 2000);
        $(this).data('timer', timer);
    }
}).blur(function() {
    clearTimeout($(this).data('timer'));     
    $(this).trigger('sync');
});

Ce qui me permet d'avoir des éléments comme celui-ci dans mon application:

<input type="text" data-url="/controller/action/" class="update">

Qui seront mis à jour lorsque l'utilisateur est "fini de taper" (aucune action pendant 2 secondes) ou à un autre champ (flou de l'élément)

0
répondu Paolo Bergantino 2012-10-25 16:33:14

Si vous avez besoin d'attendre que l'utilisateur ait fini de taper, utilisez simplement ceci:

$(document).on('change','#PageSize', function () {
    //Do something after new value in #PageSize       
});

Exemple complet avec l'appel ajax-cela fonctionne pour mon pager-nombre d'éléments par liste:

$(document).ready(function () {
    $(document).on('change','#PageSize', function (e) {
        e.preventDefault();
        var page = 1;
        var pagesize = $("#PageSize").val();
        var q = $("#q").val();
        $.ajax({
            url: '@Url.Action("IndexAjax", "Materials", new { Area = "TenantManage" })',
            data: { q: q, pagesize: pagesize, page: page },
            type: 'post',
            datatype: "json",
            success: function (data) {
                $('#tablecontainer').html(data);
               // toastr.success('Pager has been changed', "Success!");
            },
            error: function (jqXHR, exception) {
                ShowErrorMessage(jqXHR, exception);
            }
        });  
    });
});    
0
répondu Miroslav Siska 2016-01-23 22:44:54

D'accord avec la réponse de @ going. Une autre solution similaire qui a fonctionné pour moi est celle ci-dessous. La seule différence, c'est que je suis à l'aide .sur("input"...) au lieu de keyup. Cela ne capture que les changements dans l'entrée. d'autres touches comme Ctrl, Maj, etc. sont ignorés

var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms (5 seconds)

//on input change, start the countdown

$('#myInput').on("input", function() {    
    clearTimeout(typingTimer);
    typingTimer = setTimeout(function(){
        // doSomething...
    }, doneTypingInterval);
});
0
répondu Grace.io 2017-03-15 09:39:19

Pourquoi ne pas simplement utiliser onfocusout?

Https://www.w3schools.com/jsreF/event_onfocusout.asp

S'il s'agit d'un formulaire, ils laisseront toujours le focus de chaque champ de saisie afin de cliquer sur le bouton Soumettre afin que vous sachiez qu'aucune entrée ne manquera d'appeler son gestionnaire d'événements onfocusout.

0
répondu coffeeeee 2017-08-28 23:47:41

Je viens de trouver un code simple pour attendre que l'utilisateur finisse de taper:

Étape 1.définissez time out sur null puis effacez le délai d'attente actuel lorsque l'utilisateur tape.

Étape 2.trigger clear timeout à la variable define avant que l'événement keyup ne soit déclenché.

Étape 3.définir le délai d'attente pour la variable déclarée ci-dessus;

<input type="text" id="input" placeholder="please type" style="padding-left:20px;"/>
<div class="data"></div>

Code Javascript

var textInput = document.getElementById('input');
var textdata = document.querySelector('.data');
// Init a timeout variable to be used below
var timefired = null;

// Listen for keystroke events
// Init a timeout variable to be used below
var timefired = null;// Listen for keystroke events
textInput.onkeyup = function (event) {
clearTimeout(timefired);
timefired = setTimeout(function () {
    textdata.innerHTML = 'Input Value:'+ textInput.value;
  }, 600);
};
0
répondu Nevil Saul Blemuss 2018-02-09 00:53:29

Wow, même 3 commentaires sont assez corrects!

  1. L'entrée vide n'est pas une raison pour ignorer l'appel de fonction, par exemple, je supprime le paramètre waste de l'url avant de rediriger

  2. .on ('input', function() { ... }); devrait être utilisé pour déclencher keyup, paste et change événements

  3. Certainement .val() ou .value doit être utilisé

  4. Vous pouvez utiliser la fonction $(this) inside event au lieu de #id pour travailler avec plusieurs entrées

  5. (ma décision, j'utilise anonyme fonction au lieu de doneTyping dans setTimeout pour accéder facilement à $(this) de n.4, mais vous devez tout d'abord l'enregistrer comme var $currentInput = $(this);

-1
répondu vladkras 2015-08-14 13:32:35