I am trying to add an EventListener
to an <option>
Element.
I tried various ways, yet without result. I'm working with VueJS, so I tried to use their event-binding mechanic.
VueJS - Event Binding - works only on <select>
<select @mouseover="testValue = true" @mouseleave="testValue = false" ref="select">
<option v-for="(option, index) in selectionSet" :key="index"
:value="option.id" :disabled="option.disabled" @mouseover="testValue = true" @mouseleave="testValue = false">
{{option.name}}
</option>
</select>
so naturally I went the RAW plainJS way next.
PlainJS - AddEventListener() - The elements are valid, yet the eventListener will not be registered
this.$refs.select.options.forEach((el) => {
el.addEventListener('pointerover', () => { window.console.log('AAAAH'); });
if (!el.disabled) window.console.log(el.value);
});
And yes I went with multiple event names.
So what to do? -> read the docs
Looking into the <option>
documentation on MDN, I can see, that the <option>
has the HTMLOptionElement
DOM Interface. This interface is supposed to have all Properties and Methods inherited from HTMLElement
.
The HTMLOptionElement interface represents elements and inherits all properties and methods of the HTMLElement interface. - MDN
So I'm wondering, can I somehow register eventListeners to an <option>
Element?
CodePudding user response:
The problem isn't so much registering the event handler on the element, it's that browsers don't fire events at option
elements (or at least, not reliably cross-browser) in drop-down select
elements.
Chrome and Firefox, for instance, don't fire any events on option
elements in drop-down select
elements as far as I can tell, even though you can register event handlers on them and even fire your own events on them. In the below, for instance, no events are automatically fired at option
elements by Chrome or Firefox, but if you click the button to explicitly fire one at it, it works:
const option = document.querySelectorAll("option")[1];
function optionEventHandler(event) {
console.log(event.type, this.textContent);
}
// None of these fire on Chrome except when code explicitly
// does it with `dispatchEvent`, as far as I can tell:
for (const eventName of ["click", "mouseover", "pointerover", "mouseenter"]) {
option.addEventListener(eventName, optionEventHandler);
}
document.querySelector("select").addEventListener("click", function() {
console.log("click on select", this.value);
});
// Explicitly firing an event at the element:
document.querySelector("input[type=button]").addEventListener("click", function() {
option.dispatchEvent(new Event("click"));
});
<select>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
<option>E</option>
</select>
<div>
<input type="button" value="Send 'click' to B">
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
So sadly, if you want to do something when the pointer is over the option, you'll have to use something other than select
and option
. Neither Chrome nor Firefox even fires pointerover
at document
when the pointer moves from one option
to the next in a list.
For completeness, note that some events (including pointerover
) work in non-dropdown select
elements, at least on Chrome and Firefox:
const option = document.querySelectorAll("option")[1];
function optionEventHandler(event) {
console.log(event.type, this.textContent);
}
// None of these fire on Chrome except when code explicitly
// does it with `dispatchEvent`, as far as I can tell:
for (const eventName of ["click", "mouseover", "pointerover", "mouseenter"]) {
option.addEventListener(eventName, optionEventHandler);
}
document.querySelector("select").addEventListener("click", function() {
console.log("click on select", this.value);
});
// Explicitly firing an event at the element:
document.querySelector("input[type=button]").addEventListener("click", function() {
option.dispatchEvent(new Event("click"));
});
<select size="5">
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
<option>E</option>
</select>
<div>
<input type="button" value="Send 'click' to B">
</div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>