My objective is to observe an input value and trigger a handler when its value gets changed programmatically. I only need it for modern browsers.
I have tried many combinations using defineProperty
and this is my latest iteration:
var myInput=document.getElementById("myInput"); Object.defineProperty(myInput,"value",{ get:function(){ return this.getAttribute("value"); }, set:function(val){ console.log("set"); // handle value change here this.setAttribute("value",val); } }); myInput.value="new value"; // should trigger console.log and handler
This seems to do what I expect, but it feels like a hack as I am overriding the existing value property and playing with the dual status of value
(attribute and property). It also breaks the change
event that doesn't seem to like the modified property.
My other attempts:
watch
and observe
polyfills, but they break for an input value propertyWhat would be a proper way to achieve the same result?
Live demo: http://jsfiddle.net/L7Emx/4/
[Edit] To clarify: My code is watching an input element where other applications can push updates (as a result of ajax calls for example, or as a result of changes in other fields). I have no control on how the other applications push updates, I am just an observer.
[Edit 2] To clarify what I mean by "modern browser", I'd be very happy with a solution that works on IE 11 and Chrome 30.
[Update] Updated demo based on the accepted answer: http://jsfiddle.net/L7Emx/10/
The trick suggested by @mohit-jain is to add a second input for user interaction.
We can use the dispatchEvent method on an element to trigger an event programmatically. We can write: const element = document. querySelector('input'); element.
document. querySelector('#test'). addEventListener('change', () => console. log("Changed!"))
The onchange event occurs when the value of an element has been changed. For radiobuttons and checkboxes, the onchange event occurs when the checked state has been changed. Tip: This event is similar to the oninput event.
if the only problem with your solution is breaking of change event on value set. thn you can fire that event manually on set. (But this wont monitor set in case a user makes a change to the input via browser -- see edit bellow)
<html> <body> <input type='hidden' id='myInput' /> <input type='text' id='myInputVisible' /> <input type='button' value='Test' onclick='return testSet();'/> <script> //hidden input which your API will be changing var myInput=document.getElementById("myInput"); //visible input for the users var myInputVisible=document.getElementById("myInputVisible"); //property mutation for hidden input Object.defineProperty(myInput,"value",{ get:function(){ return this.getAttribute("value"); }, set:function(val){ console.log("set"); //update value of myInputVisible on myInput set myInputVisible.value = val; // handle value change here this.setAttribute("value",val); //fire the event if ("createEvent" in document) { // Modern browsers var evt = document.createEvent("HTMLEvents"); evt.initEvent("change", true, false); myInput.dispatchEvent(evt); } else { // IE 8 and below var evt = document.createEventObject(); myInput.fireEvent("onchange", evt); } } }); //listen for visible input changes and update hidden myInputVisible.onchange = function(e){ myInput.value = myInputVisible.value; }; //this is whatever custom event handler you wish to use //it will catch both the programmatic changes (done on myInput directly) //and user's changes (done on myInputVisible) myInput.onchange = function(e){ console.log(myInput.value); }; //test method to demonstrate programmatic changes function testSet(){ myInput.value=Math.floor((Math.random()*100000)+1); } </script> </body> </html>
more on firing events manually
EDIT:
The problem with manual event firing and the mutator approach is that the value property won't change when user changes the field value from browser. the work around is to use two fields. one hidden with which we can have programmatic interaction. Another is visible with which user can interact. After this consideration approach is simple enough.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With