Erkennen Sie alle Änderungen an einem <input type = “text”> (sofort) mit JQuery

397

Es gibt viele Möglichkeiten, wie sich der Wert einer <input type="text">Dose ändern kann, einschließlich:

  • Tastendruck
  • Kopieren Einfügen
  • mit JavaScript geändert
  • automatisch durch Browser oder eine Symbolleiste vervollständigt

Ich möchte, dass meine JavaScript-Funktion bei jeder Änderung (mit dem aktuellen Eingabewert) aufgerufen wird. Und ich möchte, dass es sofort aufgerufen wird, nicht nur, wenn die Eingabe den Fokus verliert.

Ich suche nach der saubersten und robustesten Möglichkeit, dies in allen Browsern zu tun (vorzugsweise mit jQuery).

Dustin Boswell
quelle

Antworten:

352

Dieser jQuery-Code erfasst sofortige Änderungen an jedem Element und sollte in allen Browsern funktionieren:

 $('.myElements').each(function() {
   var elem = $(this);

   // Save current value of element
   elem.data('oldVal', elem.val());

   // Look for changes in the value
   elem.bind("propertychange change click keyup input paste", function(event){
      // If value has changed...
      if (elem.data('oldVal') != elem.val()) {
       // Updated stored value
       elem.data('oldVal', elem.val());

       // Do action
       ....
     }
   });
 });
Phatmann
quelle
19
Für jedermanns Referenz inputist das HTML5-Ereignis, von dem ich glaube, dass es alle modernen Browser abdecken sollte ( MDN-Referenz ). keyupsollte den Rest fangen, allerdings mit einer leichten Verzögerung ( inputwird bei gedrückter Taste ausgelöst). propertychangeist ein proprietäres MS-Ereignis, und ich bin mir nicht sicher, ob pastees tatsächlich notwendig ist.
Jo Liss
71
Bin ich falsch oder dies geht nicht, wenn Text über Javascript geändert wird wiedocument.getElementById('txtInput').value = 'some text';
Mehmet Ataş
5
Mehmet, der Code ist nicht dazu gedacht, über JS geänderte Werte abzufangen.
Phatmann
12
@ MehmetAtaş ist teilweise richtig. Die Referenz für das inputEreignis hier besagt, dass es nicht ausgelöst wird, wenn der Inhalt über JavaScript geändert wird. Das onpropertychangeEreignis wird jedoch bei Änderung über JS ausgelöst (siehe hier ). Dieser Code funktioniert also, wenn der Inhalt über JS im IE geändert wird, aber nicht in anderen Browsern.
Vicky Chijwani
2
Sie können ein benutzerdefiniertes Ereignis für die Eingabe auslösen, wenn Eigenschaften geändert, verschlüsselt usw. werden, und es dann an einer beliebigen Stelle verwenden.
Ivan Ivković
122

Eine ausgefallene Echtzeitlösung für jQuery> = 1.9

$("#input-id").on("change keyup paste", function(){
    dosomething();
})

Wenn Sie auch ein "Klick" -Ereignis erkennen möchten, gehen Sie einfach wie folgt vor:

$("#input-id").on("change keyup paste click", function(){
    dosomething();
})

Wenn Sie jQuery <= 1.4 verwenden, verwenden Sie einfach liveanstelle von on.

Felix
quelle
3
Dies hat einen Nachteil. Wenn Sie das Eingabefeld mit der Tabulatortaste verlassen, wird ein Keyup-Ereignis ausgelöst, auch wenn der Inhalt nicht bearbeitet wurde.
Pawka
2
Wie erkenne ich, wann datetimepicker die # Eingabe-ID ausfüllt? Keines der Ereignisse (Ändern, Einfügen) funktioniert.
Pathros
Das ist toll! Ich habe es mit jquery 1.8.3 versucht und es funktioniert. Ich habe noch einen livequery () - Code, den ich ersetzen muss, damit ich nicht einmal auf 1.9.1 upgraden kann. Ich weiß, dass es alt ist, aber die ganze Website auch.
Asle
Zu Ihrer Information: Diese Ereignisse werden mit einem leeren Wert ausgelöst, wenn über die Tastatur ein ungültiges Datum ausgewählt wird. dh. 30. Februar stackoverflow.com/questions/48564568/…
Olmstov
107

Leider denke ich setIntervalgewinnt den Preis:

<input type=text id=input_id />
<script>
setInterval(function() { ObserveInputValue($('#input_id').val()); }, 100);
</script>

Es ist die sauberste Lösung mit nur 1 Codezeile. Es ist auch das robusteste, da Sie sich nicht um all die verschiedenen Ereignisse / Wege kümmern müsseninput um einen Wert zu erhalten.

Die Nachteile der Verwendung von 'setInterval' scheinen in diesem Fall nicht zuzutreffen:

  • Die 100ms Latenz? Für viele Anwendungen sind 100 ms schnell genug.
  • Laden im Browser hinzugefügt? Im Allgemeinen ist das Hinzufügen vieler schwerer setIntervals auf Ihrer Seite schlecht. In diesem speziellen Fall ist das Hinzufügen einer zusätzlichen Seite jedoch nicht erkennbar.
  • Es skaliert nicht auf viele Eingänge? Die meisten Seiten haben nicht mehr als eine Handvoll Eingaben, die Sie alle im selben setInterval abhören können.
Dustin Boswell
quelle
21
Dies scheint die einzige Möglichkeit zu sein, Änderungen an einem Eingabefeld in einem Formular zu erkennen, wenn der Nintendo 3DS-Browser (Version / 1.7552.EU) verwendet wird.
Johan
4
Hinweis: Überlastung kann verringert werden. Wenn Sie setInterval starten, wenn die Eingabe den Fokus erhält, und clearInterval, wenn die Eingabe den Fokus verliert
Tebe
10
Warum sollten Sie ein konstant laufendes 100-ms-Intervall erstellen, in dem es keinen Grund gibt, ständig zu laufen? EREIGNISSE Leute. Benutze sie.
Gavin
15
@ Gavin, in diesem speziellen Fall JS fehlen Ereignisse .. Finden Sie uns eine Reihe von Ereignissen, die erkennen können, Benutzereingaben, Benutzerkasten, Benutzerschnitte, Javascript-Einfügungen, Javascript-Entfernungen, automatische Vervollständigung von Formularen, versteckte Formulare, nicht angezeigt Formen.
Naramsim
2
@Gavin JS scheint kein geändertes Ereignis zu haben, das JEDES MAL ausgelöst wird, wenn eine Eingabe geändert wird. (Führen Sie einfach eine document.getElementById (name) .value = Math.random () aus, um zu sehen, dass keine der Ereignisauslöserlösungen funktioniert.
Joeri
58

Die Bindung an das oninputEreignis scheint in den meisten vernünftigen Browsern gut zu funktionieren. IE9 unterstützt es auch, aber die Implementierung ist fehlerhaft (das Ereignis wird beim Löschen von Zeichen nicht ausgelöst).

Ab jQuery Version 1.7+ ist die onMethode nützlich, um wie folgt an das Ereignis zu binden:

$(".inputElement").on("input", null, null, callbackFunction);
HRJ
quelle
12
oninputEreignis funktioniert nicht mit input[type=reset]oder Javascript-Bearbeitung, wie Sie in diesem Test sehen können: codepen.io/yukulele/pen/xtEpb
Yukulélé
2
@ Yukulélé, Zumindest können wir das einfacher umgehen, als zu versuchen, alle möglichen Benutzeraktionen zu erkennen .
Pacerier
30

Antwort 2017 : Das Eingabeereignis macht genau dies für alles, was aktueller als IE8 ist.

$(el).on('input', callback)
Chris F. Carroll
quelle
6
Entschuldigung, aber ... wie unterscheidet sich das von der Antwort von HRJ 2012 oben? Auf jeden inputFall erkennt das Ereignis keine JS-Änderungen.
David
16

Leider gibt es kein Ereignis oder eine Reihe von Ereignissen, die Ihren Kriterien entsprechen. Tastendrücke und Kopieren / Einfügen können beide mit dem keyupEreignis behandelt werden. Änderungen durch JS sind schwieriger. Wenn Sie die Kontrolle über den Code haben, mit dem das Textfeld festgelegt wird, ändern Sie ihn am besten, um entweder Ihre Funktion direkt aufzurufen oder ein Benutzerereignis im Textfeld auszulösen:

// Compare the textbox's current and last value.  Report a change to the console.
function watchTextbox() {
  var txtInput = $('#txtInput');
  var lastValue = txtInput.data('lastValue');
  var currentValue = txtInput.val();
  if (lastValue != currentValue) {
    console.log('Value changed from ' + lastValue + ' to ' + currentValue);
    txtInput.data('lastValue', currentValue);
  }
}

// Record the initial value of the textbox.
$('#txtInput').data('lastValue', $('#txtInput').val());

// Bind to the keypress and user-defined set event.
$('#txtInput').bind('keypress set', null, watchTextbox);

// Example of JS code triggering the user event
$('#btnSetText').click(function (ev) {
  $('#txtInput').val('abc def').trigger('set');
});

Wenn Sie keine Kontrolle über diesen Code haben, können Sie setInterval()das Textfeld auf Änderungen überprüfen:

// Check the textbox every 100 milliseconds.  This seems to be pretty responsive.
setInterval(watchTextbox, 100);

Diese Art der aktiven Überwachung wird Aktualisierungen nicht sofort erfassen, scheint jedoch schnell genug zu sein, dass keine Verzögerung erkennbar ist. Wie DrLouie in den Kommentaren hervorhob, lässt sich diese Lösung wahrscheinlich nicht gut skalieren, wenn Sie viele Eingaben beobachten müssen. Sie können den 2. Parameter jederzeit so einstellen, dass setInterval()er mehr oder weniger häufig überprüft wird.

Annabelle
quelle
Zu Ihrer Information, es gibt tatsächlich eine Reihe von Ereignissen, die kombiniert werden können, um die OP-Kriterien in unterschiedlichem Maße für alle Browser zu erfüllen (siehe Links im Kommentar zur ersten Frage). Diese Antwort verwendet keines der genannten Ereignisse und wird ironischerweise wahrscheinlich in allen Browsern genauso gut funktionieren, wenn auch mit einer leichten Verzögerung;)
Crescent Fresh
Das OP möchte Änderungen am Textfeld über JavaScript abfangen (z myTextBox.value = 'foo';. B. Keine JavaScript-Ereignisse behandeln diese Situation.
Annabelle
1
Was wäre, wenn jemand 50 Felder hätte, die er im Auge behalten könnte?
DoctorLouie
1
Ja, ich habe nur 1 Feld in meinem Fall, aber ich verstehe nicht, warum dies für eine Reihe von Feldern nicht angemessen funktioniert. Es wäre wahrscheinlich am effizientesten, nur 1 setTimeout zu haben, das alle Eingaben überprüft.
Dustin Boswell
1
@Douglas: Keine JavaScript-Ereignisse behandeln diese Situation - Korrektur: IE kann damit umgehen input.onpropertychange, und FF2 +, Opera 9.5, Safari 3 und Chrome 1 können damit umgehen input.__defineSetter__('value', ...)(was ich überprüfen kann, obwohl es auf DOM-Knoten als nicht funktionsfähig dokumentiert ist Es klappt). Die einzige Abweichung von der IE-Implementierung besteht darin, dass der IE den Handler nicht nur bei programmgesteuerten Einstellungen, sondern auch bei Schlüsselereignissen auslöst.
Crescent Fresh
6

Hier ist eine etwas andere Lösung, wenn Sie keine der anderen Antworten wollten:

var field_selectors = ["#a", "#b"];
setInterval(function() { 
  $.each(field_selectors, function() { 
    var input = $(this);
    var old = input.attr("data-old-value");
    var current = input.val();
    if (old !== current) { 
      if (typeof old != 'undefined') { 
        ... your code ...
      }
      input.attr("data-old-value", current);
    }   
  }   
}, 500);

Beachten Sie, dass Sie sich beim Einfügen des Kontextmenüs nicht auf Klicken und Eingeben verlassen können.

Peder
quelle
Diese Antwort hat bei mir am besten funktioniert. Ich hatte einige Probleme mit meinen Selektoren, bis ich benutzte: $("input[id^=Units_]").each(function() {
Robr
4

Fügen Sie diesen Code irgendwo hinzu, dies wird den Trick tun.

var originalVal = $.fn.val;
$.fn.val = function(){
    var result =originalVal.apply(this,arguments);
    if(arguments.length>0)
        $(this).change(); // OR with custom event $(this).trigger('value-changed');
    return result;
};

Gefunden, dass diese Lösung bei val () change () in jQuery nicht auslöst

lpradhap
quelle
3

Ich habe ein Beispiel erstellt. Möge es für Sie funktionieren.

var typingTimer;
var doneTypingInterval = 10;
var finaldoneTypingInterval = 500;

var oldData = $("p.content").html();
$('#tyingBox').keydown(function () {
    clearTimeout(typingTimer);
    if ($('#tyingBox').val) {
        typingTimer = setTimeout(function () {
            $("p.content").html('Typing...');
        }, doneTypingInterval);
    }
});

$('#tyingBox').keyup(function () {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(function () {
        $("p.content").html(oldData);
    }, finaldoneTypingInterval);
});


<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>


<textarea id="tyingBox" tabindex="1" placeholder="Enter Message"></textarea>
<p class="content">Text will be replace here and after Stop typing it will get back</p>

http://jsfiddle.net/utbh575s/

Ambuj Khanna
quelle
3

Wir müssen eigentlich keine Schleifen einrichten, um JavaScript-Änderungen zu erkennen. Wir haben bereits viele Ereignis-Listener für das Element eingerichtet, das wir erkennen möchten. Nur das Auslösen eines unschädlichen Ereignisses macht den Job.

$("input[name='test-element']").on("propertychange change click keyup input paste blur", function(){
console.log("yeh thats worked!");
});

$("input[name='test-element']").val("test").trigger("blur");

und natürlich ist dies nur verfügbar, wenn Sie die volle Kontrolle über Javascript-Änderungen in Ihrem Projekt haben.

Serdar
quelle
2

Nun, der beste Weg ist, die drei Basen abzudecken, die Sie selbst aufgelistet haben. Ein einfaches: onblur ,: onkeyup usw. funktioniert nicht für das, was Sie wollen, also kombinieren Sie sie einfach.

KeyUp sollte die ersten beiden abdecken, und wenn Javascript das Eingabefeld ändert, hoffe ich, dass es Ihr eigenes Javascript ist. Fügen Sie also einfach einen Rückruf in die Funktion ein, die es ändert.

idrumgood
quelle
1
+1 für die einfache Lösung, obwohl es möglich ist, dass OP den Code nicht ändern kann / will, indem Änderungen am Textfeld vorgenommen werden.
Annabelle
Das Aufzählen aller möglichen Ereignisse erscheint mir nicht robust. Funktioniert die Eingabe, wenn der Benutzer die Löschtaste gedrückt hält (dh eine Wiederholungstaste)? Was ist mit der automatischen Vervollständigung (oder Symbolleisten, die Werte automatisch ausfüllen)? Oder gibt es spezielle Eingabequellen, die keine Tastendrücke auslösen? Ich würde mir Sorgen machen, dass es so etwas geben würde, das Sie vermissen würden.
Dustin Boswell
1

Hier ist ein Arbeitsbeispiel, das ich zum Implementieren einer Autocomplete-Variante verwende, die einen jqueryui-Selektor (Liste) ausfüllt, aber ich möchte nicht, dass es genau wie die jqueryui-Autocomplete funktioniert, die ein Dropdown-Menü ausführt.

$("#tagFilter").on("change keyup paste", function() {
     var filterText = $("#tagFilter").val();
    $("#tags").empty();
    $.getJSON("http://localhost/cgi-bin/tags.php?term=" + filterText,
        function(data) {
            var i;
            for (i = 0; i < data.length; i++) {
                var tag = data[i].value;
                $("#tags").append("<li class=\"tag\">" + tag + "</li>");
            }
        }); 
});
klares Licht
quelle
1

KEINE JQUERY! (Es ist heutzutage sowieso irgendwie veraltet)

Bearbeiten: Ich habe die HTML-Ereignisse entfernt. Verwenden Sie KEINE HTML-Ereignisse. Verwenden Sie stattdessen Javascript-Ereignis-Listener.

document.querySelector("#testInput").addEventListener("input", test);

function test(e) {
 var a = document.getElementById('output');
 var b = /^[ -~]+$/;
 if (e.target.value == '' || b.test(e.target.value)) {
  a.innerText = "Text is Ascii?.. Yes";
 } else if (!b.test(e.target.value)) {
  a.innerText = "Text is Ascii?.. No";
 }
}
Try pressing Alt+NumPad2+NumPad3 in the input, it will instantly detect a change, whether you Paste, Type, or any other means, rather than waiting for you to unselect the textbox for changes to detect.

<input id="testInput">
<br>
<a id="output">Text is Ascii?.. Yes</a>

Herr SirCode
quelle
0

Kannst du nicht einfach ein <span contenteditable="true" spellcheck="false">Element anstelle von verwenden <input type="text">?

<span>(mit contenteditable="true" spellcheck="false"als Attribute) unterscheidet sich <input>hauptsächlich durch:

  • Es ist nicht wie ein gestylt <input>.
  • Es hat keine valueEigenschaft, aber der Text wird als gerendert innerTextund ist Teil seines inneren Körpers.
  • Es ist mehrzeilig, <input>obwohl dies nicht der Fall ist, obwohl Sie das Attribut festgelegt haben multiline="true".

Um das Erscheinungsbild zu erreichen, können Sie es natürlich in CSS formatieren, während Sie den Wert als schreiben innerText Sie dafür ein Ereignis erhalten können:

Hier ist eine Geige .

Leider gibt es etwas, das in IE und Edge nicht funktioniert, was ich nicht finden kann.

Davide Cannizzo
quelle
Ich denke, es gibt Zugänglichkeitsprobleme bei der Verwendung dieser Methode.
Daniel Tonon
0

Obwohl diese Frage vor 10 Jahren gestellt wurde, glaube ich, dass sie noch verbessert werden muss. Hier ist meine Lösung.

$(document).on('propertychange change click keyup input paste', 'selector', function (e) {
    // Do something here
});

Das einzige Problem bei dieser Lösung ist, dass sie nicht ausgelöst wird, wenn sich der Wert von Javascript wie ändert $('selector').val('some value'). Sie können jedes Ereignis in Ihrem Selektor auslösen, wenn Sie den Wert von Javascript ändern.

$(selector).val('some value');
// fire event
$(selector).trigger('change');
HaxxanRaxa
quelle
-2

Sie können dieses Beispiel sehen und auswählen, welche Ereignisse Sie interessieren:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
<title>evetns</title>
</head>
<body>
<form>
    <input class="controlevents" id="i1" type="text" /><br />
    <input class="controlevents" id="i2" type="text" /><br />
    <input class="controlevents" id="i3" type="text" /><br />
    <input class="controlevents" id="i4" type="text" /><br />
    <input class="controlevents" id="i5" type="text" /><br />
</form>
<div id="datatext"></div>
</body>
</html>
<script>
$(function(){

function testingevent(ev){
    if (ev.currentTarget.tagName=="INPUT")
        $("#datatext").append("<div>id : " + ev.currentTarget.id + ", tag: " + ev.currentTarget.tagName + ", type: "+ ev.type +"</div>");
}   

    var eventlist = ["resizeend","rowenter","dragleave","beforepaste","dragover","beforecopy","page","beforeactivate","beforeeditfocus","controlselect","blur",
                    "beforedeactivate","keydown","dragstart","scroll","propertychange","dragenter","rowsinserted","mouseup","contextmenu","beforeupdate",
                    "readystatechange","mouseenter","resize","copy","selectstart","move","dragend","rowexit","activate","focus","focusin","mouseover","cut",
                    "mousemove","focusout","filterchange","drop","blclick","rowsdelete","keypress","losecapture","deactivate","datasetchanged","dataavailable",
                    "afterupdate","mousewheel","keyup","movestart","mouseout","moveend","cellchange","layoutcomplete","help","errorupdate","mousedown","paste",
                    "mouseleave","click","drag","resizestart","datasetcomplete","beforecut","change","error","abort","load","select"];

    var inputs = $(".controlevents");

    $.each(eventlist, function(i, el){
        inputs.bind(el, testingevent);
    });

});
</script>
andres descalzo
quelle
4
Ich denke du hast einen Ereignistyp vergessen :)
Dustin Boswell
-3

Ich bin vielleicht zu spät zur Party hier, aber können Sie nicht einfach das von jQuery bereitgestellte .change () -Ereignis verwenden?

Sie sollten in der Lage sein, so etwas wie ...

$(#CONTROLID).change(function(){
    do your stuff here ...
});

Sie können es jederzeit an eine Liste von Steuerelementen mit ...

var flds = $("input, textarea", window.document);

flds.live('change keyup', function() {
    do your code here ...
});

Der Live-Ordner stellt sicher, dass alle Elemente, die jetzt und in Zukunft auf der Seite vorhanden sind, behandelt werden.

Andy Crouch
quelle
2
Das Änderungsereignis wird erst ausgelöst, nachdem der Fokus verloren gegangen ist. Es wird also nicht ausgelöst, während ein Benutzer das Feld eingibt, sondern erst, wenn er fertig ist und etwas anderes tut.
Eli Sand
2
Wie viele andere Antworten hier funktioniert dies nicht, wenn der Wert des Elements von Javascript aus geändert wird. Ich weiß nicht, ob es andere Änderungsfälle verpasst, nach denen das OP gefragt hat.
Mark Amery
-4

Dies ist der schnellste und sauberste Weg, dies zu tun:

Ich benutze Jquery ->

$('selector').on('change', function () {
    console.log(this.id+": "+ this.value);
});

Es funktioniert ziemlich gut für mich.

Despertaweb
quelle
7
Dies wurde bereits vorgeschlagen. Es werden nur einfache Fälle behandelt, in denen der Benutzer den Text eingibt.
Christophe