Wie kann ich ein Ereignis im Eingabetext auslösen, nachdem ich mit dem Schreiben aufgehört habe?

84

Ich möchte ein Ereignis auslösen, sobald ich aufhöre, Zeichen (nicht während der Eingabe) in mein Eingabetextfeld einzugeben.

Ich habe versucht mit:

$('input#username').keypress(function() {
    var _this = $(this); // copy of this object for further usage

    setTimeout(function() {
        $.post('/ajax/fetch', {
            type: 'username',
            value: _this.val()
        }, function(data) {
            if(!data.success) {
                // continue working
            } else {
                // throw an error
            }
        }, 'json');
    }, 3000);
});

In diesem Beispiel wird jedoch für jedes eingegebene Zeichen eine Zeitüberschreitung erzeugt, und ich erhalte ungefähr 20 AJAX-Anforderungen, wenn ich 20 Zeichen eingebe.

Auf dieser Geige zeige ich das gleiche Problem mit einer einfachen Warnung anstelle einer AJAX.

Gibt es eine Lösung dafür oder verwende ich dafür nur einen schlechten Ansatz?

Fuhrmanator
quelle
1
Ich befürchte, dass Javascript kein Ereignis bietet, mit dem Sie benachrichtigt werden können, wenn der Benutzer nicht mehr in ein Eingabefeld eingibt. Warum brauchst du das?
Darin Dimitrov
3
ist es nicht aus dem Beispiel ersichtlich? Ich möchte ein Ereignis auslösen, "wenn der Endbenutzer aufhört, es
1
Es gibt keine Möglichkeit zu erkennen, wann der Benutzer tatsächlich mit der Eingabe fertig ist, es sei denn, er sendet oder ändert Felder manuell. Woher wissen Sie, ob der Benutzer den mittleren Satz pausiert und 5 Minuten wartet, bevor er weitere eingibt? Eine mögliche Lösung wäre, .blur () zu verwenden und zu senden, wenn der Benutzerfokus das Feld verlässt.
Kevin M
14
Die obigen Kommentare sind albern. Dies ist ein häufiger Anwendungsfall: Ich möchte ein Ereignis, wenn der Benutzer die Größe seines Fensters geändert, die Karte gezoomt, gezogen, getippt hat. Grundsätzlich muss jede kontinuierliche Aktion des Benutzers in unser digitales Universum übersetzt werden. Sogar ein einzelner Tastendruck leidet unter diesem Problem: Wenn Sie eine Taste drücken, "springt" sie tatsächlich und erzeugt nicht nur ein Tastendruckereignis, sondern viele. Die Hardware oder das Betriebssystem Ihres Computers entfernt diese zusätzlichen Ereignisse, und deshalb haben wir die Illusion von diskreten Tastenanschlagereignissen. Dies wird als "Entprellen" bezeichnet, und dies ist das, was das OP benötigt.
Ziggy
Warnung für reagierende Benutzer: stackoverflow.com/a/28046731/57883
Maslow

Antworten:

172

Sie müssen ein setTimeout(wie Sie) verwenden, aber auch die Referenz speichern, damit Sie das Limit weiter zurücksetzen können. Etwas wie:

//
// $('#element').donetyping(callback[, timeout=1000])
// Fires callback when a user has finished typing. This is determined by the time elapsed
// since the last keystroke and timeout parameter or the blur event--whichever comes first.
//   @callback: function to be called when even triggers
//   @timeout:  (default=1000) timeout, in ms, to to wait before triggering event if not
//              caused by blur.
// Requires jQuery 1.7+
//
;(function($){
    $.fn.extend({
        donetyping: function(callback,timeout){
            timeout = timeout || 1e3; // 1 second default timeout
            var timeoutReference,
                doneTyping = function(el){
                    if (!timeoutReference) return;
                    timeoutReference = null;
                    callback.call(el);
                };
            return this.each(function(i,el){
                var $el = $(el);
                // Chrome Fix (Use keyup over keypress to detect backspace)
                // thank you @palerdot
                $el.is(':input') && $el.on('keyup keypress paste',function(e){
                    // This catches the backspace button in chrome, but also prevents
                    // the event from triggering too preemptively. Without this line,
                    // using tab/shift+tab will make the focused element fire the callback.
                    if (e.type=='keyup' && e.keyCode!=8) return;
                    
                    // Check if timeout has been set. If it has, "reset" the clock and
                    // start over again.
                    if (timeoutReference) clearTimeout(timeoutReference);
                    timeoutReference = setTimeout(function(){
                        // if we made it here, our timeout has elapsed. Fire the
                        // callback
                        doneTyping(el);
                    }, timeout);
                }).on('blur',function(){
                    // If we can, fire the event since we're leaving the field
                    doneTyping(el);
                });
            });
        }
    });
})(jQuery);

$('#example').donetyping(function(){
  $('#example-output').text('Event last fired @ ' + (new Date().toUTCString()));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<input type="text" id="example" />
<p id="example-output">Nothing yet</p>

Das wird ausgeführt, wenn:

  1. Das Timeout ist abgelaufen, oder
  2. Der Benutzer hat die Felder gewechselt ( blurEreignis)

(Welches auch immer zuerst kommt)

Brad Christie
quelle
1
Ja, das rettet meine Nacht. Vielen Dank
Neuling
2
@Brad: Diese JQuery-Lösung funktioniert einwandfrei, außer dass die im Eingabefeld eingegebene Rücktaste im neuesten Chrome (38.0.2125.111) nicht erkannt wird. Nur das Ändern in keyupfunktioniert. Möglicherweise möchten Sie dies überprüfen und den Code entsprechend ändern.
Palerdot
1
@palerdot: Gut zu wissen, danke. Ich werde mich darum kümmern und alle Änderungen zurückschicken.
Brad Christie
3
Danke für dieses Plugin - funktioniert super. Ich musste eine Anpassung vornehmen, da dies nicht funktionieren würde, wenn jemand etwas in das Eingabefeld einfügt. Ich habe die folgende Zeile so bearbeitet, dass sie paste -$el.is(':input') && $el.on('keyup keypress paste',function(e){
Matt
1
@ Sangar82: Sollte jetzt (obwohl ich ein wenig verwirrt bin, Strg + V per Tastendruck erfasst werden - es sei denn, Sie klicken mit der rechten Maustaste -> Einfügen?
Brad Christie
71

LÖSUNG:

Hier ist die Lösung. Ausführen einer Funktion, nachdem der Benutzer für eine bestimmte Zeit die Eingabe beendet hat:

var delay = (function(){
  var timer = 0;
  return function(callback, ms){
  clearTimeout (timer);
  timer = setTimeout(callback, ms);
 };
})();

Verwendung

$('input').keyup(function() {
  delay(function(){
    alert('Hi, func called');
  }, 1000 );
});
Ata ul Mustafa
quelle
1
user1386320 - Überprüfen Sie diese Lösung. Ich habe ein ähnliches Problem und es funktioniert. Sie werden Ihren Code anstelle von alert () hinzufügen.
Ata ul Mustafa
Vielen Dank. Funktioniert gut.
user1919
2
Darf ich N + Up Stimmen hinzufügen? Diese Lösung ist mit JavaScript Closures brillant, kurz und elegant.
Matteo Conta
1
@ MattoConta, danke :)
Ata ul Mustafa
1
Ich wollte underscore.js nicht nur dafür in meine Seite aufnehmen. Ihre Lösung funktioniert perfekt! Vielen Dank
Skoempie
17

Sie können underscore.js "debounce" verwenden

$('input#username').keypress( _.debounce( function(){<your ajax call here>}, 500 ) );

Dies bedeutet, dass Ihr Funktionsaufruf nach 500 ms Tastendruck ausgeführt wird. Wenn Sie jedoch vor 500 ms eine andere Taste drücken (ein anderes Tastendruckereignis wird ausgelöst), wird die vorherige Funktionsausführung ignoriert (entprellt) und die neue wird nach einem neuen 500 ms-Timer ausgeführt.

Für zusätzliche Informationen würde die Verwendung von _.debounce (func, timer, true ) bedeuten, dass die erste Funktion ausgeführt wird und alle anderen Tastendruckereignisse mit nachfolgenden 500-ms-Timern ignoriert werden.

ScorpionKing2k5
quelle
Sehr nützlich und kurz, wenn Sie bereits als lib unterstrichen haben.
Francesco Pasa
10

Du musst entprellen!

Hier ist ein jQuery-Plugin und hier ist alles, was Sie über das Entprellen wissen müssen . Wenn Sie von Google hierher kommen und Underscore den Weg in die JSoup Ihrer App gefunden hat, hat es Debounce direkt eingebrannt !

Ziggy
quelle
6

gereinigte Lösung:

$.fn.donetyping = function(callback, delay){
  delay || (delay = 1000);
  var timeoutReference;
  var doneTyping = function(elt){
    if (!timeoutReference) return;
    timeoutReference = null;
    callback(elt);
  };

  this.each(function(){
    var self = $(this);
    self.on('keyup',function(){
      if(timeoutReference) clearTimeout(timeoutReference);
      timeoutReference = setTimeout(function(){
        doneTyping(self);
      }, delay);
    }).on('blur',function(){
      doneTyping(self);
    });
  });

  return this;
};
Matrix
quelle
5

Sie sollten setTimeouteine Variable zuweisen und clearTimeoutzum Löschen beim Tastendruck verwenden.

var timer = '';

$('input#username').keypress(function() {
  clearTimeout(timer);
  timer = setTimeout(function() {
    //Your code here
  }, 3000); //Waits for 3 seconds after last keypress to execute the above lines of code
});

Geige

Hoffe das hilft.

Gibin Ealias
quelle
3

Es gibt ein einfaches Plugin, das ich gemacht habe und das genau das tut. Es erfordert viel weniger Code als die vorgeschlagenen Lösungen und ist sehr leicht (~ 0,6 kb).

Zuerst erstellen Sie ein BidObjekt, als es bumpedjederzeit möglich ist. Jede Beule verzögert das Auslösen des Bid- Rückrufs für die nächste gegebene Zeitspanne.

var searchBid = new Bid(function(inputValue){
    //your action when user will stop writing for 200ms. 
    yourSpecialAction(inputValue);
}, 200); //we set delay time of every bump to 200ms

Wenn das BidObjekt fertig ist, müssen wir bumpes irgendwie tun . Lassen Sie uns das Anstoßen anhängen keyup event.

$("input").keyup(function(){
    searchBid.bump( $(this).val() ); //parameters passed to bump will be accessable in Bid callback
});

Was hier passiert ist:

Jedes Mal, wenn der Benutzer die Taste drückt, wird das Gebot für die nächsten 200 ms verzögert (gestoßen). Wenn 200 ms vergehen, ohne erneut "gestoßen" zu werden, wird ein Rückruf ausgelöst.

Außerdem haben Sie zwei zusätzliche Funktionen zum Stoppen des Gebots (wenn der Benutzer beispielsweise die Esc-Taste gedrückt oder auf eine externe Eingabe geklickt hat) und zum sofortigen Beenden und Auslösen des Rückrufs (z. B. wenn der Benutzer die Eingabetaste drückt):

searchBid.stop();
searchBid.finish(valueToPass);
pie6k
quelle
1

Ich habe nach einem einfachen HTML / JS-Code gesucht und keinen gefunden. Dann habe ich den folgenden Code mit geschrieben onkeyup="DelayedSubmission()".

<!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>
Alfredo Lingoist Jr.
quelle
0

Warum so viel tun, wenn Sie nur eine Uhr zurücksetzen möchten?

var clockResetIndex = 0 ;
// this is the input we are tracking
var tarGetInput = $('input#username');

tarGetInput.on( 'keyup keypress paste' , ()=>{
    // reset any privious clock:
    if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

    // set a new clock ( timeout )
    clockResetIndex = setTimeout(() => {
        // your code goes here :
        console.log( new Date() , tarGetInput.val())
    }, 1000);
});

Wenn Sie an WordPress arbeiten, müssen Sie den gesamten Code in einen jQuery-Block einschließen:

jQuery(document).ready(($) => {
    /**
     * @name 'navSearch' 
     * @version 1.0
     * Created on: 2018-08-28 17:59:31
     * GMT+0530 (India Standard Time)
     * @author : ...
     * @description ....
     */
        var clockResetIndex = 0 ;
        // this is the input we are tracking
        var tarGetInput = $('input#username');

        tarGetInput.on( 'keyup keypress paste' , ()=>{
            // reset any privious clock:
            if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

            // set a new clock ( timeout )
            clockResetIndex = setTimeout(() => {
                // your code goes here :
                console.log( new Date() , tarGetInput.val())
            }, 1000);
        });
});
insCode
quelle
Wenn Sie jquery erweitern und diese Methode in mehreren Eingabeelementen verwenden möchten, ist die genehmigte Antwort die Antwort, nach der Sie suchen.
InsCode
0

Verwenden Sie das Attribut onkeyup = "myFunction ()" in <input>Ihrem HTML.

HesamJafarian
quelle
-1

In meinen Gedanken hört ein Benutzer auf zu schreiben, wenn er sich nicht auf diese Eingabe konzentriert. Dafür haben Sie eine Funktion namens "Unschärfe", die Sachen wie macht

stefanz
quelle
4
falsch! Unschärfe ist ein Ereignis, bei dem der Fokus auf ein bestimmtes Eingabefeld verloren geht. Ich muss feststellen, wann die Tastatur in dem Feld, in dem ich ein Ereignis auslösen möchte, nicht verwendet wird.