Deteksi semua perubahan pada <input type = "text"> (segera) menggunakan JQuery

397

Ada banyak cara nilai suatu <input type="text">kaleng berubah, termasuk:

  • tombol ditekan
  • salin / tempel
  • dimodifikasi dengan JavaScript
  • otomatis dilengkapi oleh peramban atau bilah alat

Saya ingin fungsi JavaScript saya dipanggil (dengan nilai input saat ini) kapan saja ia berubah. Dan saya ingin segera dipanggil, tidak hanya ketika input kehilangan fokus.

Saya mencari cara paling bersih dan paling kuat untuk melakukan ini di semua browser (lebih baik menggunakan jQuery).

Dustin Boswell
sumber

Jawaban:

352

Kode jQuery ini menangkap perubahan langsung ke elemen apa pun, dan harus berfungsi di semua browser:

 $('.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
sumber
19
Untuk referensi semua orang, inputadalah acara HTML5 yang saya percaya harus mencakup semua browser modern ( referensi MDN ). keyupharus menangkap sisanya, meskipun dengan sedikit penundaan ( inputdipicu saat tombol turun). propertychangeadalah acara MS berpemilik, dan saya tidak yakin apakah pasteitu benar-benar diperlukan.
Jo Liss
71
Apakah saya salah atau ini tidak menangani ketika teks berubah melalui javascript sepertidocument.getElementById('txtInput').value = 'some text';
Mehmet Ataş
5
Mehmet, kode tidak dimaksudkan untuk menangkap nilai yang diubah melalui JS.
phatmann
12
@ MehmetAtaş sebagian benar. Referensi untuk inputacara di sini menyatakan bahwa itu tidak menyala ketika kontennya diubah melalui JavaScript. Namun, onpropertychangeacara tersebut melakukan modifikasi terhadap modifikasi melalui JS (lihat di sini ). Jadi kode ini akan berfungsi ketika konten dimodifikasi melalui JS pada IE, tetapi tidak akan berfungsi pada browser lain.
Vicky Chijwani
2
Anda dapat memicu acara khusus pada input saat pertukaran properti, keyup dll, dan kemudian menggunakannya di mana saja.
Ivan Ivković
122

Solusi mewah waktu nyata untuk jQuery> = 1.9

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

jika Anda juga ingin mendeteksi acara "klik", cukup:

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

jika Anda menggunakan jQuery <= 1.4, gunakan saja livealih-alih on.

Felix
sumber
3
Ini memiliki kekurangan. Jika Anda meninggalkan bidang input dengan tombol tab - itu akan membuang peristiwa keyup bahkan jika konten tidak diedit.
Pawka
2
Bagaimana mendeteksi ketika datetimepicker mengisi # input-id? Tak satu pun dari peristiwa (perubahan, tempel) berfungsi.
Pathros
Ini bagus! Saya mencobanya dengan jquery 1.8.3 dan berhasil. Saya masih memiliki beberapa kode livequery () yang harus saya ganti sehingga saya tidak bisa memutakhirkannya menjadi 1.9.1. Saya tahu ini sudah tua tapi begitu juga seluruh situs web.
Asle
FYI: Peristiwa ini akan diaktifkan dengan nilai kosong jika keyboard digunakan untuk memilih tanggal yang tidak valid. yaitu. 30
Feb.
107

Sayangnya, saya pikir setIntervalmemenangkan hadiah:

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

Ini solusi terbersih, hanya 1 baris kode. Ini juga yang paling kuat, karena Anda tidak perlu khawatir tentang semua peristiwa / cara yang berbeda yang inputbisa mendapatkan nilai.

Kelemahan menggunakan 'setInterval' tampaknya tidak berlaku dalam kasus ini:

  • Latensi 100 ms? Untuk banyak aplikasi, 100 ms cukup cepat.
  • Menambahkan beban di browser? Secara umum, menambahkan banyak setInterval berat di halaman Anda buruk. Namun dalam kasus khusus ini, beban halaman yang ditambahkan tidak dapat dideteksi.
  • Itu tidak skala ke banyak input? Sebagian besar halaman tidak memiliki lebih dari beberapa input, yang dapat Anda hirup semua dalam setInterval yang sama.
Dustin Boswell
sumber
21
Ini tampaknya menjadi satu-satunya cara untuk mendeteksi perubahan pada bidang input dalam formulir saat menggunakan browser Nintendo 3DS (Versi / 1.7552.EU).
Johan
4
Catatan: Overload bisa diredakan. Jika Anda mulai mengaturInterval ketika input mendapatkan fokus dan menghapusInterval ketika input kehilangan fokus
Tebe
10
Mengapa Anda membuat interval 100ms yang terus berjalan di mana tidak ada alasan untuk itu terus berjalan? ACARA orang. Gunakan itu.
Gavin
15
@ Gavin, dalam hal ini JS kekurangan acara .. temukan kami set acara yang dapat mengenali, input pengguna, pasta pengguna, potongan pengguna, sisipan javascript, penghapusan javascript, pelengkapan otomatis formulir, formulir tersembunyi, tidak ada yang ditampilkan formulir.
Naramsim
2
@ Gavin JS tampaknya tidak memiliki acara yang diubah yang dipicu SETIAP SAAT suatu input diubah. (cukup lakukan document.getElementById (nama) .value = Math.random ()) untuk melihat tidak ada solusi pemicu acara yang berfungsi.
Joeri
58

Mengikat oninputacara tampaknya bekerja dengan baik di sebagian besar browser yang waras. IE9 mendukungnya juga, tetapi implementasinya buggy (acara tidak dipecat saat menghapus karakter).

Dengan jQuery versi 1.7+ onmetode ini berguna untuk mengikat ke acara seperti ini:

$(".inputElement").on("input", null, null, callbackFunction);
HRJ
sumber
12
oninputacara tidak berfungsi dengan input[type=reset]atau mengedit javascript seperti yang Anda lihat dalam tes ini: codepen.io/yukulele/pen/xtEpb
Yukulélé
2
@ Yukulélé, Setidaknya kita bisa mengatasi itu lebih mudah daripada mencoba mendeteksi semua tindakan pengguna yang mungkin .
Pacerier
30

Jawaban 2017 : acara input melakukan hal ini untuk sesuatu yang lebih baru dari IE8.

$(el).on('input', callback)
Chris F Carroll
sumber
6
Maaf tapi ... apa bedanya dengan jawaban HRJ 2012 di atas? Bagaimanapun, inputacara gagal mendeteksi perubahan JS.
David
16

Sayangnya tidak ada acara atau rangkaian acara yang cocok dengan kriteria Anda. Tekan tombol dan salin / tempel keduanya dapat ditangani dengan keyupacara tersebut. Perubahan melalui JS lebih sulit. Jika Anda memiliki kendali atas kode yang mengatur kotak teks, taruhan terbaik Anda adalah memodifikasinya untuk langsung memanggil fungsi Anda atau memicu acara pengguna di kotak teks:

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

Jika Anda tidak memiliki kendali atas kode itu, Anda bisa menggunakan setInterval()'melihat' kotak teks untuk perubahan:

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

Pemantauan aktif semacam ini tidak akan menangkap pembaruan 'segera', tetapi tampaknya cukup cepat sehingga tidak ada kelambatan yang terlihat. Seperti yang ditunjukkan DrLouie dalam komentar, solusi ini mungkin tidak skala dengan baik jika Anda perlu menonton banyak input. Anda selalu dapat menyesuaikan parameter ke-2 setInterval()untuk memeriksa lebih sering atau lebih sedikit.

Annabelle
sumber
FYI sebenarnya ada banyak peristiwa yang dapat digabungkan agar sesuai dengan kriteria OP dalam berbagai tingkat di seluruh browser (lihat tautan di komentar pertanyaan pertama). Jawaban ini tidak menggunakan acara mengatakan, dan ironisnya mungkin akan bekerja sama dengan baik di semua browser, meskipun dengan lag sedikit;)
Bulan Sabit Segar
OP ingin menangkap perubahan pada kotak teks melalui JavaScript (mis myTextBox.value = 'foo';. Tidak ada peristiwa JavaScript yang menangani situasi itu.)
Annabelle
1
Bagaimana jika seseorang memiliki 50 bidang yang harus diperhatikan?
DoctorLouie
1
Ya, saya hanya memiliki 1 bidang dalam kasus saya, tetapi saya tidak melihat mengapa ini tidak berfungsi dengan baik untuk sejumlah bidang. Mungkin paling efisien untuk hanya memiliki 1 setTimeout yang memeriksa semua input.
Dustin Boswell
1
@Douglas: Tidak ada peristiwa JavaScript yang menangani situasi itu - Koreksi: IE dapat mengatasinya input.onpropertychange, dan FF2 +, Opera 9.5, Safari 3, dan Chrome 1 dapat mengatasinya input.__defineSetter__('value', ...)(yang, meskipun didokumentasikan tidak berfungsi pada node DOM, saya dapat memverifikasi berhasil). Satu-satunya perbedaan dari implementasi IE adalah IE meluncurkan handler tidak hanya pada pengaturan program tetapi juga selama acara-acara utama.
Crescent Fresh
6

Ini adalah solusi yang sedikit berbeda jika Anda tidak menyukai jawaban yang lain:

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

Pertimbangkan bahwa Anda tidak dapat mengandalkan klik dan keyup untuk mengambil tempel menu konteks.

Peder
sumber
Jawaban ini paling cocok untuk saya. Saya mengalami beberapa masalah dengan penyeleksi sampai saya gunakan: $("input[id^=Units_]").each(function() {
robr
4

Tambahkan kode ini di suatu tempat, ini akan melakukan trik.

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

Menemukan solusi ini di val () tidak memicu perubahan () di jQuery

lpradhap
sumber
3

Saya telah membuat sampel. Semoga ini berhasil untuk Anda.

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
sumber
3

Kami sebenarnya tidak perlu mengatur loop untuk mendeteksi perubahan javaScript. Kami sudah menyiapkan banyak pendengar acara untuk elemen yang ingin kami deteksi. hanya memicu peristiwa yang tidak berbahaya akan membuat pekerjaan.

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

dan ofc ini hanya tersedia jika Anda memiliki kontrol penuh pada perubahan javascript pada proyek Anda.

Serdar
sumber
2

Nah, cara terbaik adalah menutupi ketiga pangkalan yang Anda daftarkan sendiri. Sederhana: onblur,: onkeyup, dll tidak akan berfungsi untuk apa yang Anda inginkan, jadi gabungkan saja.

KeyUp harus mencakup dua yang pertama, dan jika Javascript memodifikasi kotak input, saya harap ini javascript Anda sendiri, jadi tambahkan saja callback pada fungsi yang memodifikasinya.

idrumgood
sumber
1
+1 untuk solusi sederhana, meskipun OP mungkin tidak dapat / tidak ingin memodifikasi kode yang membuat perubahan pada kotak teks.
Annabelle
Menghitung semua peristiwa yang mungkin tampak tidak masuk akal bagi saya. Apakah keyup berfungsi jika pengguna menahan delete down (mis. Tombol ulang)? Bagaimana dengan pelengkapan otomatis (atau bilah alat yang secara otomatis mengisi nilai)? Atau ada sumber input khusus yang tidak memencet tombol? Saya khawatir bahwa akan ada sesuatu seperti ini yang akan Anda lewatkan.
Dustin Boswell
1

Berikut ini adalah contoh kerja yang saya gunakan untuk mengimplementasikan variasi autocomplete yang mengisi pemilih jqueryui (daftar), tapi saya tidak ingin itu berfungsi persis seperti autocomplete jqueryui yang melakukan menu drop-down.

$("#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>");
            }
        }); 
});
cahaya terang
sumber
1

TANPA JQUERY! (Jenisnya sudah usang akhir-akhir ini)

Sunting: Saya menghapus acara HTML. JANGAN gunakan acara HTML ... alih-alih gunakan Javascript Event Listeners.

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>

Tuan SirCode
sumber
0

Tidak bisakah Anda menggunakan <span contenteditable="true" spellcheck="false">elemen saja <input type="text">?

<span>(dengan contenteditable="true" spellcheck="false"sebagai atribut) dibedakan <input>terutama karena:

  • Ini tidak ditata seperti <input>.
  • Itu tidak memiliki valueproperti, tetapi teks itu dibuat innerTextdan membuat bagian dari tubuhnya.
  • Ini multiline padahal <input>bukan meskipun Anda mengatur atribut multiline="true".

Untuk mencapai penampilan, tentu saja Anda bisa menata dalam CSS, sambil menuliskan nilai yang innerTextAnda bisa dapatkan sebagai peristiwa:

Ini biola .

Sayangnya ada sesuatu yang tidak benar-benar berfungsi di IE dan Edge, yang saya tidak dapat menemukannya.

Davide Cannizzo
sumber
Saya pikir ada masalah aksesibilitas di sekitar menggunakan metode itu.
Daniel Tonon
0

Meskipun pertanyaan ini telah diposting 10 tahun yang lalu, saya percaya masih perlu beberapa perbaikan. Jadi, inilah solusi saya.

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

Satu-satunya masalah dengan solusi ini adalah, itu tidak akan memicu jika nilai berubah dari javascript suka $('selector').val('some value'). Anda dapat memecat suatu peristiwa ke pemilih Anda ketika Anda mengubah nilai dari javascript.

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

Anda dapat melihat contoh ini dan memilih acara mana yang menarik minat Anda:

<!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
sumber
4
Saya pikir Anda lupa jenis acara :)
Dustin Boswell
-3

Saya mungkin terlambat ke pesta di sini, tetapi bisakah Anda tidak hanya menggunakan acara .change () yang disediakan jQuery.

Anda harus dapat melakukan sesuatu seperti ...

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

Anda selalu dapat mengikatnya ke daftar kontrol dengan sesuatu seperti ...

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

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

Pengikat langsung memastikan bahwa semua elemen yang ada di halaman sekarang dan di masa depan ditangani.

Andy Crouch
sumber
2
Acara perubahan hanya menyala setelah fokus hilang, sehingga tidak menyala saat pengguna mengetik di kotak, hanya setelah mereka selesai dan melanjutkan untuk melakukan sesuatu yang lain.
Eli Sand
2
Seperti banyak jawaban lain di sini, ini tidak akan berfungsi ketika nilai elemen diubah dari Javascript. Saya tidak tahu apakah ia melewatkan kasus modifikasi lain yang diminta OP.
Mark Amery
-4

Ini adalah cara tercepat & bersih untuk melakukan itu:

Saya menggunakan Jquery ->

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

Ini bekerja cukup baik untuk saya.

Despertaweb
sumber
7
Ini sudah disarankan. Ini hanya menangani kasus-kasus sederhana, ketika pengguna mengetik teks.
Christophe