简体   繁体   中英

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

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: {}

Fire the change event after updating the value programmatically:

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

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM