Wykryj wszystkie zmiany w <input type = „text”> (natychmiast) za pomocą JQuery

397

Istnieje wiele <input type="text">możliwości zmiany wartości a , w tym:

  • naciśnięcia klawiszy
  • kopiuj wklej
  • zmodyfikowany za pomocą JavaScript
  • automatycznie uzupełniane przez przeglądarkę lub pasek narzędzi

Chcę, aby moja funkcja JavaScript była wywoływana (z bieżącą wartością wejściową) przy każdej zmianie. I chcę, aby to zostało wywołane od razu, nie tylko wtedy, gdy sygnał wejściowy traci ostrość.

Szukam najczystszego i najbardziej niezawodnego sposobu na zrobienie tego we wszystkich przeglądarkach (najlepiej przy użyciu jQuery).

Dustin Boswell
źródło

Odpowiedzi:

352

Ten kod jQuery przechwytuje natychmiastowe zmiany dowolnego elementu i powinien działać we wszystkich przeglądarkach:

 $('.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
źródło
19
Dla odniesienia wszyscy inputto wydarzenie HTML5, które moim zdaniem powinno obejmować wszystkie nowoczesne przeglądarki ( odniesienie MDN ). keyuppowinien złapać resztę, choć z niewielkim opóźnieniem ( inputjest uruchamiany po naciśnięciu klawisza). propertychangejest zastrzeżonym zdarzeniem stwardnienia rozsianego i nie jestem pewien, czy pastejest to faktycznie konieczne.
Jo Liss,
71
Czy się mylę, czy to nie działa, gdy tekst zmienia się za pomocą javascript, jakdocument.getElementById('txtInput').value = 'some text';
Mehmet Ataş
5
Mehmet, kod nie jest przeznaczony do przechwytywania wartości zmienionych przez JS.
phatmann
12
@ MehmetAtaş jest częściowo poprawny. Odnośnik do inputzdarzenia tutaj stwierdza, że ​​nie jest uruchamiany, gdy zawartość jest modyfikowana za pomocą JavaScript. Jednak onpropertychangezdarzenie wywołuje modyfikację za pośrednictwem JS (patrz tutaj ). Więc ten kod będzie działał, gdy zawartość zostanie zmodyfikowana za pomocą JS w IE, ale nie będzie działać w innych przeglądarkach.
Vicky Chijwani,
2
Możesz wywołać niestandardowe zdarzenie na wejściu, gdy zmiana własności, keyup itp., A następnie użyć go w dowolnym miejscu.
Ivan Ivković
122

Wymyślne rozwiązanie w czasie rzeczywistym dla jQuery> = 1.9

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

jeśli chcesz również wykryć zdarzenie „kliknięcie”, po prostu:

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

jeśli używasz jQuery <= 1.4, po prostu użyj livezamiast on.

Felix
źródło
3
Ma to wadę. Jeśli zostawisz pole wejściowe z klawiszem Tab - spowoduje to zdarzenie keyup, nawet jeśli treść nie była edytowana.
Pawka
2
Jak wykryć, kiedy datetimepicker wypełnia # ID wejściowy? Żadne ze zdarzeń (zmiana, wklej) nie działa.
Pathros,
To jest świetne! Próbowałem z jquery 1.8.3 i działa. Nadal mam kod livequery (), który muszę wymienić, więc nie mogę zaktualizować nawet do wersji 1.9.1. Wiem, że jest stary, ale cała witryna też.
Asle,
FYI: Te zdarzenia będą uruchamiane z pustą wartością, jeśli klawiatura zostanie użyta do wybrania niepoprawnej daty. to znaczy. Luty 30. stackoverflow.com/questions/48564568/...
Olmstov
107

Niestety myślę, że setIntervalwygrywa nagrodę:

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

To najczystsze rozwiązanie, tylko w 1 linii kodu. Jest również najbardziej niezawodny, ponieważ nie musisz się martwić o różne wydarzenia / sposobyinput mogą przynieść wartość.

Wady stosowania „setInterval” wydają się nie mieć zastosowania w tym przypadku:

  • Opóźnienie 100 ms? W przypadku wielu aplikacji 100 ms jest wystarczająco szybkie.
  • Dodano ładowanie w przeglądarce? Ogólnie rzecz biorąc, dodawanie dużej liczby interwałów setIv na twojej stronie jest złe. Ale w tym konkretnym przypadku dodane ładowanie strony jest niewykrywalne.
  • Nie skaluje się do wielu danych wejściowych? Większość stron nie ma więcej niż garść danych wejściowych, które można obwąchać w tym samym setInterval.
Dustin Boswell
źródło
21
Wydaje się, że jest to jedyny sposób na wykrycie zmian w polu wejściowym w formularzu podczas korzystania z przeglądarki Nintendo 3DS (wersja / 1.7552.EU).
Johan
4
Uwaga: Przeciążenie można złagodzić. Jeśli uruchomisz setInterval, gdy wejście zostanie zogniskowane, i wyczyśćInterval, gdy wejście przestanie być aktywne
Tebe
10
Dlaczego miałbyś tworzyć stale działający interwał 100 ms, gdzie nie ma powodu, aby ciągle działał? WYDARZENIA ludzie. Użyj ich.
Gavin
15
@ Gavin, w tym konkretnym przypadku brak zdarzeń w JS .. znajdź nam zestaw zdarzeń, które mogą rozpoznać, dane wejściowe użytkownika, pasty użytkownika, cięcia użytkownika, wstawianie javascript, usuwanie javascript, automatyczne uzupełnianie formularzy, ukryte formularze, brak wyświetlania formy.
Naramsim,
2
@Gavin JS nie wydaje się mieć zmienionego zdarzenia, które jest wyzwalane ZA KAŻDĄ zmianę danych wejściowych. (po prostu wykonaj document.getElementById (name) .value = Math.random ()), aby zobaczyć, że żadne rozwiązanie wyzwalacza zdarzenia nie działa.
Joeri
58

Powiązanie z oninputwydarzeniem wydaje się działać dobrze w większości rozsądnych przeglądarek. IE9 też to obsługuje, ale implementacja jest błędna (zdarzenie nie jest uruchamiane podczas usuwania znaków).

W jQuery w wersji 1.7+ onmetoda jest przydatna do powiązania ze zdarzeniem takim jak to:

$(".inputElement").on("input", null, null, callbackFunction);
HRJ
źródło
12
oninputwydarzenie nie działa z input[type=reset]edycją javascript, jak widać w tym teście: codepen.io/yukulele/pen/xtEpb
Yukulélé 15.04.2013
2
@ Yukulélé, Przynajmniej możemy to obejść łatwiej niż próbując wykryć wszystkie możliwe działania użytkownika .
Pacerier
30

Odpowiedź z 2017 r . : zdarzenie wejściowe robi dokładnie to w przypadku nowszych wersji niż IE8.

$(el).on('input', callback)
Chris F. Carroll
źródło
6
Przepraszamy, ale ... czym to się różni od powyższej odpowiedzi HRJ z 2012 r.? W każdym razie inputzdarzenie nie wykrywa zmian JS.
David
16

Niestety nie ma wydarzenia lub zestawu wydarzeń spełniających podane kryteria. Z naciśnięciem klawisza oraz kopiowaniem / wklejaniem można obsługiwać keyupzdarzenie. Zmiany w JS są trudniejsze. Jeśli masz kontrolę nad kodem, który ustawia pole tekstowe, najlepiej jest zmodyfikować go, aby bezpośrednio wywołać twoją funkcję lub wywołać zdarzenie użytkownika w polu tekstowym:

// 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');
});

Jeśli nie masz kontroli nad tym kodem, możesz setInterval()„obserwować” pole tekstowe pod kątem zmian:

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

Ten rodzaj aktywnego monitorowania nie wykrywa aktualizacji natychmiast, ale wydaje się być wystarczająco szybki, aby nie było zauważalnego opóźnienia. Jak zauważył DrLouie w komentarzach, to rozwiązanie prawdopodobnie nie skaluje się dobrze, jeśli trzeba oglądać wiele danych wejściowych. Zawsze możesz dostosować drugi parametr, setInterval()aby sprawdzać częściej lub rzadziej.

Annabelle
źródło
Do Twojej dyspozycji jest tak naprawdę wiele wydarzeń, które można łączyć w celu dopasowania kryteriów PO w różnym stopniu w różnych przeglądarkach (patrz linki w komentarzu do pierwszego pytania). Ta odpowiedź nie wykorzystuje żadnego ze wspomnianych zdarzeń i jak na ironię prawdopodobnie będzie działać równie dobrze we wszystkich przeglądarkach, choć z niewielkim opóźnieniem;)
Crescent Fresh
OP chce przechwycić zmiany w polu tekstowym za pomocą JavaScript (np myTextBox.value = 'foo';. Żadne zdarzenia JavaScript nie obsługują tej sytuacji.
Annabelle,
1
Co jeśli ktoś ma 50 pól, aby mieć na oku?
DoctorLouie,
1
Tak, w moim przypadku mam tylko 1 pole, ale nie rozumiem, dlaczego nie działałoby to dość dobrze w przypadku wielu pól. Prawdopodobnie najskuteczniej byłoby mieć tylko 1 setTimeout, który sprawdza wszystkie dane wejściowe.
Dustin Boswell,
1
@Douglas: Żadne zdarzenia JavaScript nie radzą sobie z tą sytuacją - Korekta: IE może sobie z tym poradzić input.onpropertychange, a FF2 +, Opera 9.5, Safari 3 i Chrome 1 mogą sobie z tym poradzić input.__defineSetter__('value', ...)(co, chociaż jest udokumentowane jako niedziałające w węzłach DOM, mogę zweryfikować to działa). Jedyną rozbieżnością w stosunku do implementacji IE jest to, że IE odpala program obsługi nie tylko w ustawieniach programowych, ale także podczas kluczowych zdarzeń.
Crescent Fresh
6

Oto nieco inne rozwiązanie, jeśli nie masz ochoty na inne odpowiedzi:

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);

Weź pod uwagę, że nie można polegać na kliknięciu i wprowadzeniu klucza, aby przechwycić wklej menu kontekstowego.

Peder
źródło
Ta odpowiedź działała dla mnie najlepiej. Miałem pewne problemy z moimi selektorami, dopóki nie użyłem: $("input[id^=Units_]").each(function() {
robr
4

Dodaj ten kod gdzieś, to załatwi sprawę.

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;
};

Znalazłem to rozwiązanie w val () nie powoduje zmiany () w jQuery

lpradhap
źródło
3

Stworzyłem próbkę. Niech to zadziała dla ciebie.

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
źródło
3

W rzeczywistości nie musimy konfigurować pętli do wykrywania zmian w języku Java. Już skonfigurowaliśmy wiele detektorów zdarzeń dla elementu, który chcemy wykryć. po prostu wywołanie dowolnego szkodliwego zdarzenia spowoduje, że praca będzie działać.

$("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");

i często jest to dostępne tylko wtedy, gdy masz pełną kontrolę nad zmianami javascript w swoim projekcie.

Serdar
źródło
2

Najlepszym sposobem jest pokrycie tych trzech baz, które sam wymieniłeś. Prosty: onblur,: onkeyup itp. Nie będzie działał tak, jak chcesz, więc po prostu je połącz.

KeyUp powinien obejmować pierwsze dwa, a jeśli JavaScript modyfikuje pole wprowadzania, cóż, mam nadzieję, że to twój własny JavaScript, więc po prostu dodaj wywołanie zwrotne w funkcji, która go modyfikuje.

idrumgood
źródło
1
+1 za proste rozwiązanie, chociaż jest możliwe, że OP nie może / nie chce modyfikować kodu wprowadzającego zmiany w polu tekstowym.
Annabelle,
Wyliczenie wszystkich możliwych zdarzeń nie wydaje mi się wiarygodne. Czy keyup działa, jeśli użytkownik przytrzyma klawisz Delete (tj. Klawisz powtarzania)? Co z autouzupełnianiem (lub paskami narzędzi, które automatycznie wypełniają wartości)? Czy istnieją specjalne źródła wejściowe, które nie uruchamiają naciśnięć klawiszy? Martwiłbym się, że byłoby coś takiego, za czym byś tęsknił.
Dustin Boswell
1

Oto działający przykład, którego używam do implementacji wariantu autouzupełniania, który wypełnia selektor (listę) jqueryui, ale nie chcę, aby działał dokładnie tak samo jak autouzupełnianie jqueryui, które robi menu rozwijane.

$("#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>");
            }
        }); 
});
jasne światło
źródło
1

BEZ JQUERY! (W każdym razie jest to trochę przestarzałe)

Edycja: usunąłem zdarzenia HTML. NIE używaj zdarzeń HTML ... zamiast tego używaj nasłuchiwania zdarzeń JavaScript.

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>

Pan SirCode
źródło
0

Nie możesz po prostu użyć <span contenteditable="true" spellcheck="false">elementu zamiast <input type="text">?

<span>(z contenteditable="true" spellcheck="false"atrybutami as) różni się <input>głównie dlatego, że:

  • To nie jest stylizowane jak <input>.
  • Nie ma valuewłaściwości, ale tekst jest renderowany jako innerTexti stanowi część jego wewnętrznego ciała.
  • Jest wielowierszowy, <input>ale nie jest, mimo że ustawisz atrybut multiline="true".

Aby uzyskać wygląd, możesz oczywiście nadać mu styl CSS, jednocześnie wpisując wartość jako innerText jaką można uzyskać dla zdarzenia:

Tutaj jest skrzypce .

Niestety jest coś, co tak naprawdę nie działa w IE i Edge, czego nie mogę znaleźć.

Davide Cannizzo
źródło
Myślę, że istnieją obawy dotyczące dostępności związane z użyciem tej metody.
Daniel Tonon
0

Chociaż to pytanie zostało opublikowane 10 lat temu, uważam, że nadal wymaga ono pewnych ulepszeń. Oto moje rozwiązanie.

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

Jedynym problemem związanym z tym rozwiązaniem jest to, że nie uruchomi się, jeśli wartość zmieni się w stosunku do javascript $('selector').val('some value'). Możesz zmienić dowolne zdarzenie na selektor, zmieniając wartość z javascript.

$(selector).val('some value');
// fire event
$(selector).trigger('change');
HaxxanRaxa
źródło
-2

możesz zobaczyć ten przykład i wybrać, które wydarzenia Cię interesują:

<!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
źródło
4
Myślę, że zapomniałeś typu wydarzenia :)
Dustin Boswell
-3

Mogę spóźnić się na imprezę tutaj, ale czy nie możesz po prostu użyć zdarzenia .change (), które zapewnia jQuery.

Powinieneś być w stanie zrobić coś takiego ...

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

Zawsze możesz powiązać go z listą kontrolek za pomocą czegoś takiego jak ...

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

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

Aktywny segregator zapewnia obsługę wszystkich elementów istniejących na stronie teraz i w przyszłości.

Andy Crouch
źródło
2
Zdarzenie zmiany jest uruchamiane tylko po utracie skupienia, więc nie jest uruchamiane, gdy użytkownik pisze w polu, tylko po ich zakończeniu i zrobieniu czegoś innego.
Eli Sand
2
Podobnie jak wiele innych odpowiedzi tutaj, to nie zadziała, gdy wartość elementu zostanie zmodyfikowana z Javascript. Nie wiem, czy pomija inne przypadki modyfikacji, o które poprosił PO.
Mark Amery
-4

To najszybszy i czysty sposób na zrobienie tego:

Używam Jquery ->

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

Dla mnie działa całkiem dobrze.

Despertaweb
źródło
7
Zostało to już zasugerowane. Dotyczy tylko prostych przypadków, gdy użytkownik wpisuje tekst.
Christophe