10

I've got an input with google autoComplete connected.

When the user moves up and down through the seachResultsthe value of the input is changed dynamically via JavaScript.

I'd like to capture the value that is in the input at any given time.

I've tried onChange and onInput but since no event is getting fired, and the value of the DOM Node is not getting set - there are no updates.

How do you detect changes to the input that are dynamically updated via JavaScript?

zero_cool
  • 3,494
  • 4
  • 37
  • 50
  • `the value of the DOM Node is not getting set` Wait, is the value being changed via Javascript, or not? Title implies it is, but that line there implies that it's not? – CertainPerformance Mar 06 '19 at 23:33
  • Make no mistake - the value of the input does change - I believe via Google - but the value attribute does not update unless an event is fired. For example, if onBlur or onClick is fired - the value attribute updates but when the results are changed via google autoComplete - it does not. – zero_cool Mar 06 '19 at 23:34
  • 1
    The value *attribute* shouldn't change, though the value *property* should. How are you determining that it doesn't update, are you just listening for an event and not seeing one that triggers the listener? A live snippet (or a link) that illustrates the behavior would probably clear things up significantly – CertainPerformance Mar 06 '19 at 23:35
  • Potato? Potawto? What do you mean by property? The DOM Node of the input has a value attribute. When I'm watching the DOM using the browser inspector the value does not change unless an event is fired. – zero_cool Mar 06 '19 at 23:37

2 Answers2

9

The .value attribute will only change if the script-writer has called setAttribute('value' to set the new value, which is quite an odd thing to do. In almost all situations, I would expect the value to be set by assigning to the value property directly, eg:

input.value = 'foo';

Calling setAttribute will indeed show a change in the inspected DOM attribute, eg:

<input value="somevalue">

const input = document.querySelector('input');
input.setAttribute('value', 'foo');
console.log(input.outerHTML);
<input>

But just assigning to the .value property of the element will not result in such a change:

const input = document.querySelector('input');
input.value = 'foo';
console.log(input.outerHTML);
<input>

Assigning to the .value actually invokes a setter function on HTMLInputElement.prototype:

console.log(HTMLInputElement.prototype.hasOwnProperty('value'));

You can shadow this by putting a getter/setter for value directly on the element itself, with the setter invoking your own function, allowing you to listen for changes:

const { get, set } = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
const input = document.querySelector('input');
Object.defineProperty(input, 'value', {
  get() {
    return get.call(this);
  },
  set(newVal) {
    console.log('New value assigned to input: ' + newVal);
    return set.call(this, newVal);
  }
});


// example of autocomplete trying to change the input value:
input.value = 'foo';
<input>
CertainPerformance
  • 313,535
  • 40
  • 245
  • 254
2

Consider creating and triggering input events

var event = new Event('input', {
    bubbles: true,
    cancelable: true,
});

then

myelement.dispatchEvent(event);

more info

Khaled Alshammari
  • 1,946
  • 3
  • 14
  • 33