Home > Enterprise >  How can I respond to an input element's value property being set?
How can I respond to an input element's value property being set?

Time:07-02

I'm writing a user script which needs to respond to an <input> element's value changing, no matter how the change was made.

For user interactions, this is easy — just add a listener for the input event. However, I haven't yet found a way to respond to the input's value being set directly by changing its .value property.

I've tried adding listeners for the change and input events (neither are triggered) and adding a MutationObserver for both the input's attributes and the input's parent's child list (again, neither are triggered). There also doesn't appear to be a property descriptor I can modify.

How can I trigger code to run when an <input> element's .value property is set?

<!DOCTYPE html>
<html>
  <head>
    <title>Detect value change</title>

    <script type="module">
      const range = document.querySelector('input');

      range.addEventListener('change', (event) => console.log('Change:', event));
      range.addEventListener('input', (event) => console.log('Input:', event));

      const observer = new MutationObserver((mutations) => console.log('Mutation:', mutations));

      observer.observe(range, { attributes: true, attributeFilter: ['value'] });
      observer.observe(range.parentNode, { childList: true });

      console.log('Property descriptors:', Object.getOwnPropertyDescriptors(range));

      // Somewhere else, in code I don't control:
      document.querySelector('input').value = 7;
    </script>
  </head>

  <body>
    <input type="range" min="0" max="10" />
  </body>
</html>

Console output:

Property descriptors: {}

CodePudding user response:

Fire the change event after updating the value programmatically:

range.value = 7;
var event = new Event('change');
range.dispatchEvent(event);

CodePudding user response:

See this answer for great information on why MutationObserver will not catch modifications to properties.

If you are unable to modify the way the value is being changed (node.setAttribute('value', 'newValue') would fire your MutationObserver, for example), then I think your only option is unfortunately a setInterval that poles for value changes at a set frequency.

Something like this:

const range = document.querySelector('input');

document.getElementById('incrementValue').addEventListener('click', () => {
 const val = range.valueAsNumber;
 range.value = range.value === range.max ? range.min : String(val   1);
});

let currentVal;
setInterval(() => {
 // Check for val changes every 1sec
 if (range.value === currentVal) {
  return;
 }
 currentVal = range.value;
 console.log(`New value detected. New value is ${range.value}`);
}, 1000);
<!DOCTYPE html>
<html>

<head>
  <title>Detect value change</title>
</head>

<body>
  <button id="incrementValue">Increment value</button>
  <input type="range" min="0" max="10" value="0" />
</body>

</html>

  • Related