Виявити всі зміни <вхідного типу = "тексту"> (негайно) за допомогою JQuery


397

Існує багато способів зміни цінності <input type="text">, зокрема:

  • натискання клавіш
  • Копіювати Вставити
  • змінено 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
       ....
     }
   });
 });

19
Для довідок для всіх, чи inputє подія HTML5, яка, на мою думку, повинна охоплювати всі сучасні браузери ( посилання MDN ). keyupповинен спіймати решту, хоча з невеликою затримкою ( inputспрацьовує при натисканні клавіші). propertychangeє власною подією MS, і я не впевнений, чи pasteдійсно це необхідно.
Джо Лісс

71
Я помиляюся чи це не document.getElementById('txtInput').value = 'some text';
вирішується,

5
Мехмет, код не призначений для лову значень, змінених через JS.
phatmann

12
@ MehmetAtaş частково правильний. Посилання на inputподію тут вказує, що воно не працює, коли зміст змінено через JavaScript. Однак onpropertychangeподія запускає модифікацію через JS (див. Тут ). Таким чином, цей код буде працювати, коли вміст модифікується через JS на IE, але не працюватиме в інших браузерах.
Vicky Chijwani

2
Ви можете запустити власну подію на вході при зміні властивостей, клавіатурі тощо, а потім використовувати її будь-де.
Іван Івкович

122

Фантастичне рішення в реальному часі для jQuery> = 1.9

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

якщо ви також хочете виявити подію "натисніть", просто:

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

якщо ви використовуєте jQuery <= 1.4, просто використовуйте liveзамість on.


3
Це має недолік. Якщо ви залишите поле введення за допомогою клавіші табуляції - воно викине подію клавіатури, навіть якщо вміст не редагувався.
Pawka

2
Як визначити, коли добірка часу заповнює # input-id? Жодна з подій (змінити, вставити) не працює.
Pathros

Це чудово! Я спробував це з jquery 1.8.3, і він працює. У мене ще є код livequery (), який я маю замінити, тому не можу повністю оновити навіть 1.9.1. Я знаю, що це старий, але так є і весь веб-сайт.
Asle

FYI: Ці події запускаються з порожнім значенням, якщо клавіатура використовується для вибору дати, що не відповідає дійсності. тобто. Лютого 30. stackoverflow.com/questions/48564568 / ...
Olmstov

107

На жаль, я думаю, setIntervalвиграє приз:

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

Це найчистіше рішення з лише 1 рядком коду. Це також є найбільш надійним, оскільки вам не доведеться турбуватися про всі різні події / способи, inputщоб отримати цінність.

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

  • Затримка на 100 мс? Для багатьох застосувань 100 мс досить швидко.
  • Додано завантаження браузера? Загалом, додавання великої кількості важких вагових інтернетів на вашу сторінку погано. Але в цьому конкретному випадку додане завантаження сторінки не виявляється.
  • Він не масштабується до багатьох входів? Більшість сторінок не мають декількох входів, якими ви можете нюхати всіх в одному наборі інтернету.

21
Це, мабуть, є єдиним способом виявлення змін у полі введення у формі при використанні браузера Nintendo 3DS (Версія / 1.7552.EU).
Йоган

4
Примітка: Перевантаження можна полегшити. Якщо ви запускаєте setInterval, коли вхід отримує фокус, а яснийInterval, коли вхід втрачає фокус
Tebe

10
Чому б ви створювали постійний інтервал 100 мс, коли немає причини, щоб він постійно працював? ПОДІЇ люди. Використовуйте їх.
Гавін

15
@Gavin, в цьому конкретному випадку JS не вистачає подій .. знайдіть нам набір подій, які можна розпізнати, введення користувачів, вставки користувачів, вирізання користувачів, вставки javascript, видалення javascript, автоматичне заповнення форм, приховані форми, не відображаються форм.
Нарамсім

2
@Gavin JS, схоже, не змінився події, яке запускається ВСЕ ТАКОЖ, а вхід змінюється. (просто зробіть document.getElementById (ім'я) .value = Math.random ()), щоб побачити, що жодне рішення тригера подій не працює.
Joeri

58

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

За допомогою jQuery версії 1.7+ onметод корисно прив’язувати до такої події:

$(".inputElement").on("input", null, null, callbackFunction);

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
Вибачте, але ... чим це відрізняється від відповіді ВРЮ 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);

Цей вид активного моніторингу не оновлює оновлення "негайно", але, здається, це досить швидко, щоб не було помітного відставання. Як в коментарях зазначив ДрЛуї, це рішення, ймовірно, не має кращих масштабів, якщо вам потрібно спостерігати за великими даними. Ви завжди можете налаштувати другий параметр, setInterval()щоб перевіряти більш-менш часто.


FYI насправді є цілий ряд подій, які можна комбінувати для відповідності критеріям ОП в різному ступені в браузерах (див. Посилання в коментарі до першого питання). Ця відповідь не використовує жодної із зазначених подій, і, за іронією долі, напевно, спрацює так само добре у всіх браузерах, хоча і з невеликим відставанням;)
Crescent Fresh

ОП хоче зафіксувати зміни в текстовому полі через JavaScript (наприклад, myTextBox.value = 'foo';жодні події JavaScript не вирішують цю ситуацію.
Annabelle

1
Що робити, якщо хтось мав 50 полів для збереження вкладок?
DoctorLouie

1
Так, у мене є лише 1 поле в моєму випадку, але я не бачу, чому це не спрацює досить добре для ряду полів. Напевно, найефективнішим є лише 1 setTimeout, який перевіряє всі входи.
Дастін Босуелл

1
@Douglas: Жодна подія JavaScript не справляється з цією ситуацією - Виправлення: IE може впоратись із нею input.onpropertychange, а FF2 +, Opera 9.5, Safari 3 та Chrome 1 можуть впоратися з цим input.__defineSetter__('value', ...)(що, хоча це документально не функціонує на вузлах DOM, я можу перевірити це працює). Єдина розбіжність від впровадження IE - IE запускає обробник не тільки на програмних налаштуваннях, але й під час ключових подій.
Півмісяць Свіжий

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 () не викликає зміни () у 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/


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

і ofc це доступно лише в тому випадку, якщо ви маєте повний контроль над змінами javascript у своєму проекті.


2

Ну, найкращий спосіб - охопити ці три бази, які ви самі перерахували. Просте: onblur,: onkeyup тощо не працюватиме для того, що ви хочете, тому просто поєднайте їх.

KeyUp повинен охоплювати перші два, і якщо Javascript модифікує поле введення, то я впевнений, що сподіваюся, що це ваш власний JavaScript, тому просто додайте зворотний виклик у функцію, яка його змінює.


1
+1 для простого рішення, хоча можливо, що ОП не може / не хоче змінювати код, вносячи зміни в текстове поле.
Аннабель

Перерахування всіх можливих подій мені не здається надійним. Чи працює клавіатура, якщо користувач утримує видалення (тобто повторний ключ)? А як щодо автоматичного заповнення (або панелей інструментів, які автоматично заповнюють значення)? Або є спеціальні джерела введення, які не спрацьовують натискання клавіш? Я б хвилювався, що щось подібне ви б пропустили.
Дастін Босуелл

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

НЕ БУДУТЬ! (Його нинішній день все-таки застарів)

Редагувати: я видалив події 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>


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

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

Для мене це працює досить добре.


7
Це вже було запропоновано. Він стосується лише простих випадків, коли користувач вводить текст.
Крістоф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.