Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger action on programmatic change to an input value

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:

  • a setTimeout/setInterval loop, but this is not clean either
  • various watch and observe polyfills, but they break for an input value property

What 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.

like image 432
Christophe Avatar asked Oct 11 '13 19:10

Christophe


People also ask

How do you programmatically trigger change events?

We can use the dispatchEvent method on an element to trigger an event programmatically. We can write: const element = document. querySelector('input'); element.

How can I trigger an Onchange event manually in JavaScript?

document. querySelector('#test'). addEventListener('change', () => console. log("Changed!"))

What event can you listen to when the value is changed by JavaScript?

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.


1 Answers

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.

  1. mutate value property on hidden input-field to observe the changes and fire manual onchange event. on set value change the value of visible field to give user feedback.
  2. on visible field value change update the value of hidden for observer.
like image 132
Mohit Avatar answered Sep 29 '22 05:09

Mohit