Trigger action on programmatic change to an input

2020-01-29 04:32发布

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.

7条回答
疯言疯语
2楼-- · 2020-01-29 05:27

Since you are already using polyfills for watch/observe, etc, let me take the opportunity to suggest to you Angularjs.

It offers exactly this functionality in the form of it's ng-models. You can put watchers on the model's value, and when it changes, you can then call other functions.

Here is a very simple, but working solution to what you want:

http://jsfiddle.net/RedDevil/jv8pK/

Basically, make a text input and bind it to a model:

<input type="text" data-ng-model="variable">

then put a watcher on the angularjs model on this input in the controller.

$scope.$watch(function() {
  return $scope.variable
}, function(newVal, oldVal) {
  if(newVal !== null) {
    window.alert('programmatically changed');
  }
});
查看更多
登录 后发表回答