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

397

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

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

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

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

Дастин Босвелл
источник

Ответы:

352

Этот код 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
       ....
     }
   });
 });
phatmann
источник
19
На inputмой взгляд, событие HTML5 должно охватывать все современные браузеры ( ссылка на MDN ). keyupОстальное следует ловить, правда, с небольшой задержкой ( inputсрабатывает при нажатии клавиши вниз). propertychangeэто запатентованное событие MS, и я не уверен, pasteдействительно ли это необходимо.
Джо Лисс
71
Я ошибаюсь, или это не обрабатывается, когда текст изменяется с помощью JavaScript, какdocument.getElementById('txtInput').value = 'some text';
Mehmet Ataş
5
Мехмет, код не предназначен для перехвата значений, измененных с помощью JS.
phatmann
12
@ MehmetAtaş частично верно. Ссылка на inputсобытие здесь утверждает, что оно не срабатывает, когда содержимое модифицируется с помощью JavaScript. Тем не менее, onpropertychangeсобытие происходит при модификации через JS (см. Здесь ). Таким образом, этот код будет работать, когда содержимое будет изменено через JS в IE, но не будет работать в других браузерах.
Вики Чиджвани
2
Вы можете инициировать пользовательское событие на входе при изменении свойства, keyup и т. Д., А затем использовать его где угодно.
Иван Ивкович
122

Необычное решение в реальном времени для 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.

Феликс
источник
3
Это имеет недостаток. Если вы оставите поле ввода с клавишей табуляции - оно выдаст событие keyup, даже если содержимое не было отредактировано.
Pawka
2
Как определить, когда datetimepicker заполняет # input-id? Ни одно из событий (изменить, вставить) не работает.
Патрос
Это замечательно! Я попробовал это с jquery 1.8.3, и это работает. У меня все еще есть какой-то код livequery (), который я должен заменить, поэтому я не могу обновить его до 1.9.1. Я знаю, что это старый, но так же весь сайт.
Asle
К вашему сведению: эти события будут запускаться с пустым значением, если клавиатура используется для выбора недопустимой даты. то есть. Февраль 30. stackoverflow.com/questions/48564568/...
Olmstov
107

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

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

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

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

  • Задержка 100 мс? Для многих приложений 100 мс достаточно быстро.
  • Добавлена ​​загрузка в браузер? В общем, добавление большого количества тяжеловесных setIntervals на вашей странице плохо. Но в данном конкретном случае добавленная загрузка страницы не обнаруживается.
  • Это не масштабируется до многих входов? Большинство страниц имеют не более нескольких входных данных, которые вы можете прослушать в одном наборе setInterval.
Дастин Босвелл
источник
21
Похоже, что это единственный способ обнаружить изменения в поле ввода в форме при использовании браузера Nintendo 3DS (Version / 1.7552.EU).
Йохан
4
Примечание: перегрузка может быть ослаблена. Если вы запускаете setInterval, когда ввод получает фокус, и clearInterval, когда ввод теряет фокус
Tebe
10
Зачем вам создавать постоянно работающий интервал в 100 мс, когда нет причин для его постоянной работы? СОБЫТИЯ люди. Используй их.
Гэвин
15
@Gavin, в данном конкретном случае в JS отсутствуют события ... найдите нам наборы событий, которые могут распознать, пользовательские вводы, вставки пользователя, вырезки пользователя, вставки javascript, удаление javascript, автозаполнение форм, скрытые формы, не отображаемые формы.
Нарамсим
2
@Gavin JS, похоже, не имеет события onbound, которое срабатывает КАЖДЫЙ раз, когда ввод изменяется. (просто сделайте document.getElementById (name) .value = Math.random ()), чтобы увидеть, что ни одно из решений для запуска событий не работает.
Джори
58

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

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

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

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

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

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

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

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

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

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

Аннабель
источник
К вашему сведению, на самом деле существует множество событий, которые можно комбинировать, чтобы в разной степени соответствовать критериям OP в разных браузерах (см. Ссылки в комментарии к первому вопросу). Этот ответ не использует ни одно из упомянутых событий, и по иронии судьбы, вероятно, будет работать одинаково хорошо во всех браузерах, хотя и с небольшой задержкой;)
Crescent Fresh
ОП хочет перехватить изменения в текстовом поле с помощью JavaScript (например, в myTextBox.value = 'foo';этой ситуации нет событий JavaScript.
Аннабель
1
Что если бы у кого-то было 50 полей, чтобы следить за ними?
Доктор Луи
1
Да, у меня есть только 1 поле в моем случае, но я не понимаю, почему это не будет работать достаточно хорошо для ряда полей. Вероятно, было бы наиболее эффективно иметь 1 setTimeout, который проверяет все входные данные.
Дастин Босвелл
1
@Douglas: Никакие события JavaScript не обрабатывают эту ситуацию - Исправление: IE может справиться с этим input.onpropertychange, и FF2 +, Opera 9.5, Safari 3 и Chrome 1 могут справиться с этим input.__defineSetter__('value', ...)(что, хотя это задокументировано как не работающее на узлах DOM, я могу проверить оно работает). Единственное отличие от реализации IE заключается в том, что IE запускает обработчик не только при программной настройке, но и во время ключевых событий.
Crescent Fresh
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);

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

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

Добавьте этот код куда-нибудь, это поможет.

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

lpradhap
источник
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/

Амбудж Ханна
источник
3

На самом деле нам не нужно настраивать циклы для обнаружения изменений 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");

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

Сердар
источник
2

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

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

idrumgood
источник
1
+1 для простого решения, хотя возможно, что OP не может / не хочет изменять код, внося изменения в текстовое поле.
Аннабель
Перечисление всех возможных событий не кажется мне убедительным. Работает ли keyup, если пользователь удерживает клавишу delete (т. Е. Клавишу повтора)? Как насчет автозаполнения (или панелей инструментов, которые автоматически заполняют значения)? Или есть специальные источники ввода, которые не запускают нажатия клавиш? Я бы волновался, что будет что-то подобное, что ты упустишь.
Дастин Босвелл
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>");
            }
        }); 
});
ClearLight
источник
1

НЕТ JQUERY! (Это в любом случае устарело в наши дни)

Изменить: я удалил события HTML. НЕ используйте события HTML ... вместо этого используйте прослушиватели событий 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>

Мистер SirCode
источник
0

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

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

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

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

Вот скрипка .

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

Давиде Канниццо
источник
Я думаю, что есть проблемы доступности, связанные с использованием этого метода.
Даниэль Тонон
0

Хотя этот вопрос был опубликован 10 лет назад, я считаю, что он все еще нуждается в некоторых улучшениях. Так вот мое решение.

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

Единственная проблема с этим решением заключается в том, что оно не сработает, если значение изменится с JavaScript $('selector').val('some value'). Вы можете вызвать любое событие для вашего селектора, когда вы измените значение с JavaScript.

$(selector).val('some value');
// fire event
$(selector).trigger('change');
HaxxanRaxa
источник
-2

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

<!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
Я думаю, что вы забыли тип события :)
Дастин Босвелл
-3

Я могу опоздать на вечеринку, но вы не можете просто использовать событие .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. Я не знаю, пропускает ли он какие-либо другие модификации, о которых просил ОП.
Марк Амери
-4

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

Я использую Jquery ->

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

Это работает довольно хорошо для меня.

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