Detect programmatic changes on input type text

Is there a way to get informed when a script changes the value of an input type text.

I have

<input id='test' type='text' />

and a script

document.getElementById('test').value = 'bbb'; 

I want to be notified of the change of the text.

I know I could be notified by keydown,keyup, onblur etcetera (which works if I am trying to track user typing) but what about if the change is done programmatically ?

Many thanks

p.s. No JQuery please or if jquery does it can somebody explain how it achieves it.


Solution 1:

If you're dealing with a modern browser, you can try with something like this:

var input = document.getElementById('test');
input._value = input.value;
Object.defineProperty(input, "value", {
    get: function() {return this._value;},
    set: function(v) {
        // Do your stuff
        this._value = v;
    }
});

This solution is good if you actually don't expect any user input (i.e., hidden type input fields), because it's extremely destructive of the DOM basic functionality. Keep that in mind.

Solution 2:

I find the simplest way is to actually trigger the event manually:

document.getElementById('test').value = 'bbb';
var evt = new CustomEvent('change');
document.getElementById('test').dispatchEvent(evt);

Just listening to the change event is error-prone when the value is changed programmatically. But since you are changing the value, add two lines and fire the change event, with a CustomEvent.

then you'll be able to catch this change event, either inline:

<input id="test" onchange="console.log(this)">

or with a listener:

document.getElementById('test').addEventListener('change',function(event) {
    console.log(event.target);
});

this have the advantage that if you have an input which can be changed by the user, you can catch both those events (from the user or the script)

this however depends on the fact that you are yourself programmatically changing the value of the input. If you are using libraries (such as datepickr) that change the values of your inputs you may have to get in the code and add those two lines at the right place.

Live Demo:

// input node reference
const inputElem = document.querySelector('input')

// bind "change" event listener
inputElem.addEventListener('change', e => console.log(e.target.value))

// programatically change the input's value every 1 second
setInterval(() => { 
  // generate random value
  inputElem.value = Math.random() * 100 | 0; 
  
  // simulate the "change" event
  var evt = new CustomEvent('change')
  inputElem.dispatchEvent(evt)
}, 1000);
<input>