436

There are many ways the value of a <input type="text"> can change, including:

  • keypresses
  • copy/paste
  • modified with JavaScript
  • auto-completed by browser or a toolbar
  • form reset

I want my JavaScript function to be called (with the current input value) any time it changes. And I want it to be called right away, not just when the input loses focus.

I'm looking for the cleanest and most robust way to do this across all browsers (using jQuery preferably).

2

16 Answers 16

364

This jQuery code uses .bind() to catch immediate changes to any element, and should work across all browsers:

 $('.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
       ....
     }
   });
 });

However, note that .bind() was deprecated in jQuery version 3.0. Anyone using jQuery version 1.7 or newer should use .on() instead.

Sign up to request clarification or add additional context in comments.

13 Comments

For everyone's reference, input is the HTML5 event that I believe should cover all modern browsers (MDN reference). keyup should catch the rest, though with a slight delay (input is triggered on key down). propertychange is a proprietary MS event, and I'm not sure if paste is actually necessary.
Am I wrong or this does not handle when text changed via javascript like document.getElementById('txtInput').value = 'some text';
Mehmet, the code is not meant to catch values changed via JS.
@MehmetAtaş is partly correct. The reference for the input event here states that it does not fire when the contents are modified via JavaScript. However, the onpropertychange event does fire on modification via JS (see here). So this code will work when the contents are modified via JS on IE, but will not work on other browsers.
You can trigger a custom event on the input when propertychange, keyup etc , and then use it anywhere.
|
130

A real-time solution for jQuery >= 1.7 is on

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

if you also want to detect "click" event, just:

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

if you're using jQuery <= 1.6, just use bind or live instead of on.

5 Comments

This has a drawback. If you leave input field with tab key - it will throw keyup event even if content was not edited.
How to detect when datetimepicker fills the #input-id? None of the events (change, paste) work.
This is great! I tried it with jquery 1.8.3 and it works. I still have some livequery() code I have to replace so I can't quite upgrade to even 1.9.1. I know it is old but so is the whole website.
FYI: These events will fire with a blank value if the keyboard is used to select a date that is not valid. ie. Feb 30. stackoverflow.com/questions/48564568/…
Note that these events won't fire if the value was changed via JavaScript.
121

Unfortunately, I think setInterval wins the prize:

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

It's the cleanest solution, at only 1 line of code. It's also the most robust, since you don't have to worry about all the different events/ways an input can get a value.

The downsides of using 'setInterval' don't seem to apply in this case:

  • The 100ms latency? For many applications, 100ms is fast enough.
  • Added load on the browser? In general, adding lots of heavy-weight setIntervals on your page is bad. But in this particular case, the added page load is undetectable.
  • It doesn't scale to many inputs? Most pages don't have more than a handful of inputs, which you can sniff all in the same setInterval.

17 Comments

This appears to be the only way to detect changes to an input field in a form when using the Nintendo 3DS browser (Version/1.7552.EU).
Note: Overload can be eased. If you start setInterval when input gets focus and clearInterval when input lost focus
Why would you create a constantly running 100ms interval where there's no reason for it to be constantly running? EVENTS people. Use them.
@Gavin, in this particular case JS lacks of events.. find us a sets of events that can recognize, user inputs, user pastes, user cuts, javascript insertions, javascript removals, auto-completitions of forms, hidden forms, none-displayed forms.
@Gavin JS does not seem to have a onchanged event that is triggered EVERYTIME an input is changed. ( just do a document.getElementById(name).value = Math.random() ) to see none of the event trigger solutions work.
|
62

Binding to the input event seems to work fine in most sane browsers. IE9 supports it too, but the implementation is buggy (the event is not fired when deleting characters).

With jQuery version 1.7+ the on method is useful to bind to the event like this:

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

2 Comments

oninput event don't works with input[type=reset] or javascript editing as you can see in this test: codepen.io/yukulele/pen/xtEpb
@Yukulélé, At least we can work around that more easily than trying to detect all possible user action.
17

Unfortunately there is no event or set of events that matches your criteria. Keypresses and copy/paste can both be handled with the keyup event. Changes through JS are trickier. If you have control over the code that sets the textbox, your best bet is to modify it to either call your function directly or trigger a user event on the textbox:

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

If you don't have control over that code, you could use setInterval() to 'watch' the textbox for changes:

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

This sort of active monitoring won't catch updates 'immediately', but it seems to be fast enough that there is no perceptible lag. As DrLouie pointed out in comments, this solution probably doesn't scale well if you need to watch lots of inputs. You can always adjust the 2nd parameter to setInterval() to check more or less frequently.

19 Comments

FYI there are actually a slew of events that can be combined to match the OPs criteria in varying degrees across browsers (see links in first question comment). This answer does not use any of said events, and ironically will probably work just as well in all browsers, albeit with a slight lag ;)
The OP wants to catch changes to the textbox via JavaScript (e.g. myTextBox.value = 'foo';. No JavaScript events handle that situation.
What if someone had 50 fields to keep tabs on?
Yes, I only have 1 field in my case, but I don't see why this wouldn't work reasonably well for a number of fields. It would probably be most efficient to just have 1 setTimeout that checks all inputs.
@Douglas: No JavaScript events handle that situation - Correction: IE can handle it with input.onpropertychange, and FF2+, Opera 9.5, Safari 3, and Chrome 1 can handle it with input.__defineSetter__('value', ...) (which, although it's documented as not functional on DOM nodes, I can verify it works). The only divergence from IE's implementation is IE fires the handler not only on programmatic setting but also during key events.
|
13

Here is a solution that doesn't make use of jQuery (Its really quite obsolete and not necessary these days)

Using the event "input" you can look for any kind of change:

Deleting, Backspacing, Pasting, Typing, anything that will change the inputs value.

The input event is directly related to the text input. ANY time the text is changed in ANY fashion, input is dispatched.

document.querySelector("#testInput").addEventListener("input", test);

function test(e) {
    var a = document.getElementById('output');
    a.innerText += "Detected an Update!\n";
}
<input id="testInput">
<br>
<a id="output"></a>

2 Comments

@Tylor I offered a simpler solution. jQuery has too many examples of the XY problem. If people want shortcuts, they really shouldn't be programming. Especially when the shortcuts are more performance heavy or resource hungry... Also this answer was from 2019. A little late to be complaining when its been on this network and actively uploaded for almost three years.
This of course fails to handle the specific scenario that the OP outlined, changes via javascript don't trigger it.
7

Here is a slightly different solution if you didn't fancy any of the other answers:

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

Consider that you cannot rely on click and keyup to capture context menu paste.

1 Comment

This answer worked best for me. I was having some problems with my selectors till I used: $("input[id^=Units_]").each(function() {
4

Add this code somewhere, this will do the trick.

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

Found this solution at val() doesn't trigger change() in jQuery

Comments

3

I have created a sample. May it will work for you.

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/

Comments

3

We actually don't need to setup loops for detecting javaScript changes. We already setting up many event listeners to the element we want to detect. just triggering any un harmful event will make the job.

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

and ofc this is only available if you have the full control on javascript changes on your project.

Comments

3

Although this question was posted 10 years ago, I believe that it still needs some improvements. So here is my solution.

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

The only problem with this solution is, it won't trigger if the value changes from javascript like $('selector').val('some value'). You can fire any event to your selector when you change the value from javascript.

$(selector).val('some value');
// fire event
$(selector).trigger('change');

Or in a single line

$(selector).val('some value').trigger('change');

Comments

2

Well, best way is to cover those three bases you listed by yourself. A simple :onblur, :onkeyup, etc won't work for what you want, so just combine them.

KeyUp should cover the first two, and if Javascript is modifying the input box, well I sure hope it's your own javascript, so just add a callback in the function that modifies it.

1 Comment

Enumerating all the possible events doesn't seem robust to me. Does keyup work if the user holds delete down (i.e. a repeat-key)? What about auto-complete (or toolbars that auto-fill values)? Or are there are special input sources that don't fire keypresses? I'd be worried that there would be something like this that you would miss.
1

Here's a working example that I'm using to implement an autocomplete variation the populates a jqueryui selector (list), but I don't want it to function exactly like the jqueryui autocomplete which does a drop-down menu.

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

Comments

0

Can't you just use <span contenteditable="true" spellcheck="false"> element in place of <input type="text">?

<span> (with contenteditable="true" spellcheck="false" as attributes) distincts by <input> mainly because:

  • It's not styled like an <input>.
  • It doesn't have a value property, but the text is rendered as innerText and makes part of its inner body.
  • It's multiline whereas <input> isn't although you set the attribute multiline="true".

To accomplish the appearance you can, of course, style it in CSS, whereas writing the value as innerText you can get for it an event:

Here's a fiddle.

Unfortunately there's something that doesn't actually work in IE and Edge, which I'm unable to find.

1 Comment

I think there are accessibility concerns around using that method.
0

you can simply identify all changers in the form, like this

           //when form change, show aleart
            $("#FormId").change(function () {
                aleart('Done some change on form');
            }); 

Comments

0

You can bind the 'input' event to <input type="text">. This will trigger every time the input changes such as copy, paste, keypress, and so on.

$("#input-id").on("input", function(){
    // Your action
})

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.