admin管理员组

文章数量:1296908

I'd like to subscribe for all changes of value property in all inputs using custom setter:

Object.defineProperty(HTMLInputElement.prototype, 'value', {
    set: function(newValue) {
       // do some logic here

       // WHAT PUT HERE to call "super setter"?
    }
});

If I use this.value = newValue; I'm getting Maximum call stack size exceeded which is quite right but...

Nevermind. What should I call to change value in correct way? Here is JSFIDDLE with more detailed explanation.

I'd like to subscribe for all changes of value property in all inputs using custom setter:

Object.defineProperty(HTMLInputElement.prototype, 'value', {
    set: function(newValue) {
       // do some logic here

       // WHAT PUT HERE to call "super setter"?
    }
});

If I use this.value = newValue; I'm getting Maximum call stack size exceeded which is quite right but...

Nevermind. What should I call to change value in correct way? Here is JSFIDDLE with more detailed explanation.

Share asked Oct 29, 2016 at 15:31 Remek AmbroziakRemek Ambroziak 82410 silver badges11 bronze badges 1
  • My answer to this question (which is currently the accepted answer) was incorrect. I suggest changing the accepted answer to this one. If you do, please ping me so I can delete my answer. Happy coding! – T.J. Crowder Commented Nov 8, 2022 at 8:15
Add a ment  | 

5 Answers 5

Reset to default 8

Yes, this can be achieved using JavaScript:

(function (realHTMLInputElement) {
    Object.defineProperty(HTMLInputElement.prototype, 'value', {
        set: function (value) {
            // Do some logic here
            return realHTMLInputElement.set.call(this, value);
        },
    });
}(Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')));

We use a IIFE to pass in the original definition for value and then call the original set function from within our new definition.

If you bine that with a capture input event handler on document,¹ you get notified of all changes, whether via code (through the above) or by the user.

function yourCustomLogic(input, value) {
    console.log(`${input.id ? "Input #" + input.id : "An input"} set to "${value}"`);
}

// Catch programmatic changes
(function (realHTMLInputElement) {
    Object.defineProperty(HTMLInputElement.prototype, "value", {
        set: function (value) {
            // Do some logic here
            yourCustomLogic(this, value);
            return realHTMLInputElement.set.call(this, value);
        },
    });
})(Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value"));

// Catch end-user changes
document.addEventListener(
    "input",
    (event) => {
        if (event.target.tagName === "INPUT") {
            yourCustomLogic(event.target, event.target.value);
        }
    },
    true  // Capture handler
);

document.getElementById("example").value = "Updated by code.";
<input type="text" id="example">

The reason for using a capture phase handler (rather than bubbling phase) is twofold:

  1. Officially, input doesn't bubble, although most (all?) current browsers bubble it despite what the spec says

  2. It prevents event handlers that stop propagation from stopping the event before it gets to document

This worked for me. Define the value property for specific instance of HTMLInputElement, so you can use parent's value property.

// A specific instance of HTMLInputElement
var txt = document.getElementById('txtInputTagId');

// define value property for your input instance
Object.defineProperty(txt, 'value', {
    set: function(newValue) {
        var valueProp = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
        valueProp.set.call(txt, newValue);

        // Do some logic here
        console.log('setted');
    }
});

This answer was incorrect. Please see my update to this answer, which captures changes both via code and via user input.

cristian.d solution worked, but it needs also getter to be set:

function logOnInputChange(obj) {
    var valueProp = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
    // define value property for your input instance
    Object.defineProperty(obj, 'value', {
        set: function(newValue) {
            console.debug(this,'value',this.value,'=>',newValue);
            console.trace();
            valueProp.set.call(this, newValue);
        },
        get : valueProp.get,
    }); 
}

this is to show how it is used:

<input id=i1 value="init value" type=text />

and onload handler:

var inp;
window.onload = function () {
    inp = document.getElementById('i1');
    inp.value = "init value set by onload";
    console.log('input value:',inp.value);
    logOnInputChange(inp);
    inp.value = "hello!";
    console.log('input value:',inp.value);
};

just added following code

return this.defaultValue = newValue;

https://developer.mozilla/en-US/docs/Web/API/HTMLInputElement

本文标签: javascriptSetter for HTMLInputElementvalueStack Overflow