最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Event when input value is changed by JavaScript? - Stack Overflow

programmeradmin7浏览0评论

What is the event when an <input> element's value is changed via JavaScript code? For example:

$input.value = 12;

The input event is not helping here because it's not the user who is changing the value.

When testing on Chrome, the change event isn't fired. Maybe because the element didn't lose focus (it didn't gain focus, so it can't lose it)?

What is the event when an <input> element's value is changed via JavaScript code? For example:

$input.value = 12;

The input event is not helping here because it's not the user who is changing the value.

When testing on Chrome, the change event isn't fired. Maybe because the element didn't lose focus (it didn't gain focus, so it can't lose it)?

Share Improve this question edited Aug 16, 2017 at 9:16 dodov 5,8443 gold badges44 silver badges78 bronze badges asked Feb 23, 2017 at 22:44 pery mimonpery mimon 8,3157 gold badges56 silver badges65 bronze badges 5
  • 3 There is no event when the value is changed by Javascript. – Barmar Commented Feb 23, 2017 at 22:45
  • @Kinduser no... – epascarello Commented Feb 23, 2017 at 22:46
  • While there are some exceptions, events are mostly fired only due to external actions that affect the browser, not from Javascript code. – Barmar Commented Feb 23, 2017 at 22:46
  • @Kinduser "No" is the full answer. – epascarello Commented Feb 23, 2017 at 22:47
  • I can't seem to locate a non jQuery duplicate such as stackoverflow.com/questions/30291801/… – epascarello Commented Feb 23, 2017 at 22:50
Add a comment  | 

8 Answers 8

Reset to default 19

There is no built-in event for that. You have at least four choices:

  1. Any time you change $input.value in code, call the code you want triggered by the change
  2. Poll for changes
  3. Give yourself a method you use to change the value, which will also do notifications
  4. (Variant of #3) Give yourself a property you use to change the value, which will also do notifications

Of those, you'll note that #1, #3, and #4 all require that you do something in your code differently from just $input.value = "new value"; Polling, option #2, is the only one that will work with code that just sets value directly.

Details:

  1. The simplest solution: Any time you change $input.value in code, call the code you want triggered by the change:

    $input.value = "new value";
    handleValueChange();
    
  2. Poll for changes:

    var last$inputValue = $input.value;
    setInterval(function() {
        var newValue = $input.value;
        if (last$inputValue != newValue) {
            last$inputValue = newValue;
            handleValueChange();
        }
    }, 50); // 20 times/second
    

    Polling has a bad reputation (for good reasons), because it's a constant CPU consumer. Modern browsers dial down timer events (or even bring them to a stop) when the tab doesn't have focus, which mitigates that a bit. 20 times/second isn't an issue on modern systems, even mobiles.

    But still, polling is an ugly last resort.

    Example:

    var $input = document.getElementById("$input");
    var last$inputValue = $input.value;
    setInterval(function() {
        var newValue = $input.value;
        if (last$inputValue != newValue) {
            last$inputValue = newValue;
            handleValueChange();
        }
    }, 50); // 20 times/second
    function handleValueChange() {
        console.log("$input's value changed: " + $input.value);
    }
    // Trigger a change
    setTimeout(function() {
        $input.value = "new value";
    }, 800);
    <input type="text" id="$input">

  3. Give yourself a function to set the value and notify you, and use that function instead of value, combined with an input event handler to catch changes by users:

    $input.setValue = function(newValue) {
        this.value = newValue;
        handleValueChange();
    };
    $input.addEventListener("input", handleValueChange, false);
    

    Usage:

    $input.setValue("new value");
    

    Naturally, you have to remember to use setValue instead of assigning to value.

    Example:

    var $input = document.getElementById("$input");
    $input.setValue = function(newValue) {
        this.value = newValue;
        handleValueChange();
    };
    $input.addEventListener("input", handleValueChange, false);
    function handleValueChange() {
        console.log("$input's value changed: " + $input.value);
    }
    // Trigger a change
    setTimeout(function() {
        $input.setValue("new value");
    }, 800);
    <input type="text" id="$input">

  4. A variant on #3: Give yourself a different property you can set (again combined with an event handler for user changes):

    Object.defineProperty($input, "val", {
        get: function() {
            return this.value;
        },
        set: function(newValue) {
            this.value = newValue;
            handleValueChange();
        }
    });
    $input.addEventListener("input", handleValueChange, false);
    

    Usage:

    $input.val = "new value";
    

    This works in all modern browsers, even old Android, and even IE8 (which supports defineProperty on DOM elements, but not JavaScript objects in general). Of course, you'd need to test it on your target browsers.

    But $input.val = ... looks like an error to anyone used to reading normal DOM code (or jQuery code).

    Before you ask: No, you can't use the above to replace the value property itself.

    Example:

    var $input = document.getElementById("$input");
    Object.defineProperty($input, "val", {
        get: function() {
            return this.value;
        },
        set: function(newValue) {
            this.value = newValue;
            handleValueChange();
        }
    });
    $input.addEventListener("input", handleValueChange, false);
    function handleValueChange() {
        console.log("$input's value changed: " + $input.value);
    }
    // Trigger a change
    setTimeout(function() {
        $input.val = "new value";
    }, 800);
    <input type="text" id="$input">

Based on @t-j-crowder and @maciej-swist answers, let's add this one, with ".apply" function that prevent infinite loop without redefining the object.

 function customInputSetter(){

  var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
  var originalSet = descriptor.set;

  // define our own setter
  descriptor.set = function(val) {
    console.log("Value set", this, val);
    originalSet.apply(this,arguments);
  }

  Object.defineProperty(HTMLInputElement.prototype, "value", descriptor);
}

I'd add a 5th option based on T.J. Crowder suggestions. But instead of adding new property You could change the actual "value" property to trigger additional action when set - either for the specific input element, or for all input objects:

//First store the initial descriptor of the "value" property:

var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
var inputSetter = descriptor.set;

//Then modify the "setter" of the value to notify when the value is changed:

descriptor.set = function(val) {

    //changing to native setter to prevent the loop while setting the value
    Object.defineProperty(this, "value", {set:inputSetter});
    this.value = val;

    //Custom code triggered when $input.value is set
    console.log("Value set: "+val);

    //changing back to custom setter
    Object.defineProperty(this, "value", descriptor);   
}

//Last add the new "value" descriptor to the $input element
Object.defineProperty($input, "value", descriptor);

Instead of changing the "value" property for specific input element, it can be changed generically for all input elements:

Object.defineProperty(HTMLInputElement.prototype, "value", descriptor);

This method works only for change of value with javascript e.g. input.value="new value". It doesn't work when keying in the new value in the input box.

Here is a solution to hook the value property changed for all inputs:

var valueDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");

HTMLInputElement.prototype.addInputChangedByJsListener = function(cb) {
    if(!this.hasOwnProperty("_inputChangedByJSListeners")) {
        this._inputChangedByJSListeners = [];
    }
    this._inputChangedByJSListeners.push(cb);
}

Object.defineProperty(HTMLInputElement.prototype, "value", {
    get: function() {
        return valueDescriptor.get.apply(this, arguments);
    },
    set: function() {
        var self = this;
        valueDescriptor.set.apply(self, arguments);
        if(this.hasOwnProperty("_inputChangedByJSListeners")){
            this._inputChangedByJSListeners.forEach(function(cb) {
                cb.apply(self);
            })
        }
    }
});

Usage example:

document.getElementById("myInput").addInputChangedByJsListener(function() {
    console.log("Input changed to \"" + this.value + "\"");
});

One possible strategy is to use a mutationObserver to detect changes in attributes as follows:

var observer = new MutationObserver(function(mutations) {
          mutations.forEach(function(){
                 console.log('hello')});
          });

          observer.observe($input, {
                 attributes: true
          });

Although this in itself will not detect a change like:

$input.value = 12

it WILL detect a change of the actual value attribute:

$input.setAttribute('value', 12)

So if it is you that is setting the value programatically, just be sure to alter the attribute alongside the value = 12 statement and you can have the desired result.

A simple way is just to trigger an input event when you change the value.

You can do this in plain javascript.

Early in your script, put something like this:

let inputEvent = new Event('input',{bubbles:true,cancelable: true});

You can change 'input' to the event you want, 'change', 'blur', etc

Then, any time you change a value, just call this event on the same element

input.value = 12;// <- your example
input.dispatchEvent(inputEvent);// <- calling an event

This is vanilla javascript

I don't think there is an event that will cover all the programatically assigned scenarios for an input. But, I can tell you that you can programatically "fire" an event (a custom event, a regular event or just trigger an event handler[s])

It appears to me that you're using jQuery, and so, you could use:

$('input#inputId').val('my new value...').triggerHandler('change');

In that example, you're assigning a value, and forcing a call to the handler (or handlers) binded with the "change" event.

Event when input value is changed by JavaScript?

We can use event triggering with target.dispashEvent, as explained in this question.

Example with a text input:

const input = document.querySelector('.myTextInput'); 
    
//Create the appropriate event according to needs
const change = new InputEvent('change');
  
//Change the input value
input.value = 'new value';

//Fire the event;
const isNotCancelled = input.dispatchEvent(change);

When any handler on that event type doesn't use event.preventDefault(), isNotCancelled will be true, otherwise, it will be false.

发布评论

评论列表(0)

  1. 暂无评论