Обнаружить все изменения в <input type = “text”> (немедленно), используя JQuery

344

Существует множество способов изменения значения <input type="text">, в том числе:

  • нажатия клавиш
  • копировать/вставить
  • изменено с помощью JavaScript
  • автозаполнение браузером или панелью инструментов

Я хочу, чтобы моя функция JavaScript вызывалась (с текущим значением ввода) в любое время, когда она изменяется. И я хочу, чтобы он сразу вызывался, а не только когда вход теряет фокус.

Я ищу самый чистый и самый надежный способ сделать это во всех браузерах (желательно с помощью jQuery).

Пример использования: на странице Twitter Registration значение поля имени пользователя отображается в URL-адресе " http://twitter/ имя пользователя" ниже.

Теги:

16 ответов

97
Лучший ответ

К сожалению, я думаю, что setInterval выигрывает приз:

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

Это самое чистое решение, всего в 1 строке кода. Он также является самым надежным, так как вам не нужно беспокоиться обо всех различных событиях/способах, которые input может получить значение.

Недостатки использования 'setInterval', похоже, не применяются в этом случае:

  • Задержка в 100 мс? Для многих приложений 100 мс достаточно быстро.
  • Добавлена ​​нагрузка на браузер? В целом, добавление большого количества setIntervals на вашей странице плохое. Но в этом конкретном случае добавленная загрузка страницы не обнаруживается.
  • Он не масштабируется для многих входов? На большинстве страниц не более нескольких входов, которые вы можете обнюхивать в одном и том же setInterval.
  • 0
    Принимая во внимание, что некоторые другие ответы, предположительно, не в состоянии перехватить модификации input через Javascript, не будет ли альтернативой перехват всех событий, которые может инициировать модификация пользователем, а также чтобы все модификации элементов ввода посредством кода использовали функцию-обертку что явно вызывает событие изменения на элементе ввода? Это будет иметь свои недостатки (риск неосторожного отказа от использования функции-обертки; не будет работать для библиотеки / плагина на чужой странице; требует изменения существующего кода), но устранит задержку; возможно перечислить оба подхода и сравнить?
  • 1
    Здесь размещены другие фрагменты кода, но вот один из них основан на этом посте: codepen.io/chrisfargen/pen/qbyaG
Показать ещё 14 комментариев
316

Этот код jQuery мгновенно заменяет любой элемент и должен работать во всех браузерах:

 $('.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
       ....
     }
   });
 });
  • 17
    Для справки, input - это событие HTML5, которое, как я считаю, должно охватывать все современные браузеры ( ссылка на MDN ). keyup должен поймать все остальное, хотя и с небольшой задержкой ( input запускается при нажатии клавиши). propertychange - это проприетарное событие MS, и я не уверен, действительно ли необходима paste .
  • 1
    Важно отметить, что до IE 9 onpropertychange не всплывал. Это означает, что невозможно связать это событие с помощью .live() (или .on() в полезных случаях), если вы не связываете его непосредственно с самим элементом ввода.
Показать ещё 12 комментариев
97

Приятное решение в режиме реального времени для jquery >= 1.9

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

если вы также хотите обнаружить событие "click", просто:

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

если ваш jquery <= 1.4, просто используйте "live" вместо "on".

  • 2
    Это имеет недостаток. Если вы оставите поле ввода с помощью клавиши табуляции - оно выдаст событие keyup, даже если содержимое не было отредактировано.
  • 2
    Как определить, когда datetimepicker заполняет # input-id? Ни одно из событий (изменить, вставить) не работает.
Показать ещё 2 комментария
57

Привязка к событию oninput, похоже, отлично работает в большинстве здравомыслящих браузеров. IE9 также поддерживает его, но реализация ошибочна (событие не запускается при удалении символов).

С помощью jQuery версии 1.7+ метод on полезен для привязки к событию следующим образом:

$(".inputElement").on("input", null, null, callbackFunction);
  • 11
    Событие oninput не работает с input[type=reset] или редактированием javascript, как вы видите в этом тесте: codepen.io/yukulele/pen/xtEpb
  • 2
    @ Yukulélé, по крайней мере, мы можем обойти это легче, чем пытаться обнаружить все возможные действия пользователя .
22

2017 ответ: входное событие делает именно это для чего-то более нового, чем IE8.

$(el).on('input', callback)
  • 4
    Извините, но ... как это отличается от ответа HRJ 2012 года выше? В любом случае, событие input не может обнаружить изменения JS.
15

К сожалению, нет событий или событий, соответствующих вашим критериям. Ключи и копирование/вставка могут обрабатываться с событием keyup. Изменения через JS более сложны. Если у вас есть контроль над кодом, который устанавливает текстовое поле, лучше всего изменить его, чтобы либо вызвать вашу функцию напрямую, либо вызвать пользовательское событие в текстовом поле:

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

Если у вас нет контроля над этим кодом, вы можете использовать setInterval() для просмотра текстового поля для изменений:

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

Такой активный мониторинг не будет сразу же проверять обновления, но он кажется достаточно быстрым, чтобы не было заметного отставания. Как отметил ДрЛуи в комментариях, это решение, вероятно, не очень хорошо масштабируется, если вам нужно смотреть много материалов. Вы всегда можете настроить 2-й параметр на setInterval(), чтобы проверить более или менее часто.

  • 0
    К вашему сведению, на самом деле существует множество событий, которые можно комбинировать, чтобы в разной степени соответствовать критериям OP в разных браузерах (см. Ссылки в комментарии к первому вопросу). Этот ответ не использует ни одно из упомянутых событий, и по иронии судьбы, вероятно, будет работать одинаково хорошо во всех браузерах, хотя и с небольшой задержкой;)
  • 0
    ОП хочет отловить изменения в текстовом поле с помощью JavaScript (например, myTextBox.value = 'foo'; этой ситуации нет событий JavaScript.
Показать ещё 17 комментариев
6

Вот несколько другое решение, если вы не представили ни одного из других ответов:

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

Считайте, что вы не можете полагаться на клик и клавиатуру для захвата вставки контекстного меню.

  • 0
    Этот ответ работал лучше всего для меня. У меня были некоторые проблемы с моими селекторами, пока я не использовал: $("input[id^=Units_]").each(function() {
3

Добавьте этот код где-нибудь, это сделает трюк.

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

Нашел это решение в val() не вызывает change() в jQuery

3

Я создал образец. Пусть это сработает для вас.

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/

2

На самом деле нам не нужно настраивать циклы для обнаружения изменений javaScript. Мы уже настраиваем множество прослушивателей событий для элемента, который мы хотим обнаружить. просто запуск любого нежелательного события сделает работу.

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

и ofc это доступно только в том случае, если у вас есть полный контроль над изменениями javascript в вашем проекте.

1

Здесь рабочий пример, который я использую для реализации вариации автозаполнения, заполняет селектор (список) jqueryui, но я не хочу, чтобы он функционировал точно так же, как автозаполнение jqueryui, которое выдает раскрывающееся меню.

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

Хорошо, лучший способ состоит в том, чтобы покрыть те три базы, которые вы указали сами. Простой: onblur,: onkeyup и т.д. Не будут работать для того, что вы хотите, поэтому просто соедините их.

KeyUp должен охватывать первые два, и если Javascript изменяет поле ввода, я уверен, надеюсь, что это ваш собственный javascript, поэтому просто добавьте обратный вызов в функцию, которая его модифицирует.

  • 1
    +1 для простого решения, хотя возможно, что OP не может / не хочет изменять код, внося изменения в текстовое поле.
  • 0
    Перечисление всех возможных событий не кажется мне убедительным. Работает ли keyup, если пользователь удерживает клавишу delete (т. Е. Клавишу повтора)? Как насчет автозаполнения (или панелей инструментов, которые автоматически заполняют значения)? Или есть специальные источники ввода, которые не запускают нажатия клавиш? Я бы волновался, что будет что-то подобное, что ты упустишь.
0

Не можете ли вы использовать элемент <span contenteditable="true" spellcheck="false"> вместо <input type="text">?

<span>contenteditable="true" spellcheck="false" в качестве атрибутов) выделяется <input> главным образом потому, что:

  • Это не стиль, как <input>.
  • У него нет свойства value, но текст отображается как innerText и составляет часть его внутреннего тела.
  • Он многострочный, тогда как <input> нет, хотя вы устанавливаете атрибут multiline="true".

Чтобы выполнить внешний вид, вы можете, конечно, стилизовать его в CSS, а записывая значение innerText, вы можете получить для него событие:

Здесь fiddle.

К сожалению, есть что-то, что на самом деле не работает в IE и Edge, которые я не могу найти.

  • 0
    Я думаю, что есть проблемы доступности для использования этого метода.
-1

вы можете увидеть этот пример и выбрать, какие события вас интересуют:

<!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>
  • 4
    Я думаю, что вы забыли тип события :)
-2

Возможно, я опаздываю на вечеринку, но не могу ли вы просто использовать событие .change(), которое предоставляет jQuery.

Вы должны иметь возможность сделать что-то вроде...

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

Вы всегда можете привязать его к списку элементов управления с чем-то вроде...

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

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

Связывание в реальном времени гарантирует, что все элементы, которые существуют на странице сейчас и в будущем, обрабатываются.

  • 2
    Событие изменения срабатывает только после потери фокуса, поэтому оно не срабатывает, когда пользователь печатает в поле, только после того, как он закончил и продолжил делать что-то еще.
  • 2
    Как и многие другие ответы здесь, это не будет работать, когда значение элемента изменяется из Javascript. Я не знаю, пропускает ли он какие-либо другие модификации, о которых просил ОП.
-3

Это самый быстрый & чистый способ сделать это:

Я использую JQuery →

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

Он работает отлично для меня.

  • 7
    Это уже было предложено. Это касается только простых случаев, когда пользователь печатает текст.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню