Reputation: 1432
I have multiple selects on a page, like this:
<select id="select-1" class="action">
<option val=1>1</option>
<option val=2>2</option>
</select>
<select id="select-2">
<option val=1>1</option>
<option val=2>2</option>
</select>
<select id="select-3" class="action">
<option val=1>1</option>
<option val=2>2</option>
</select>
I need to do some actions with JS code when selects with class "action" are changed.
I could do something like this:
var elements = document.getElementsByClassName("classname");
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', myFunction, false);
}
But maybe there is a better way to handle this.
So my question is: what is the best way to use one event handler to handle multiple select elements?
Upvotes: 0
Views: 952
Reputation: 22320
First of all : your html is invalid : options element has value attribute , no val, and this value must have quotes around.
so <option val=1>1</option>
is wrong,
and must be <option value="1">1</option>
for event delegation, you need to have a parent element.
As your code are about select elements, the logic parent should be a <form>
element.
and for the selects, the main event is a change event, not a click event
last things, all form element must have a name, this name is used when the form is submited , and not the id.
the other interest to use name attribute in forms, is they can be directly used to reference any sub element of the form
so the complete code is:
const myForm = document.forms['my-form']
// get any -change- event on all the form
myForm.addEventListener('change', myFunction, false)
// event delegation function
function myFunction(evt)
{
// ignore other cases:
if (!evt.target.matches('select.action')) return
console.clear()
console.log( 'change on :', evt.target.name )
console.log( 'value is', myForm[evt.target.name].value )
}
// disable form submit
myForm.onsubmit =evt=>evt.preventDefault()
<form action="" name="my-form">
<select name="select-1" class="action">
<option value="s1_1"> s1 -1 </option>
<option value="s1_2"> s1 -2 </option>
</select>
<select name="select-2">
<option value="s2_11"> s2 -1 </option>
<option value="s2_12"> s2 -2 </option>
</select>
<select name="select-3" class="action">
<option value="s3_11"> s3 -1 </option>
<option value="s3_12"> s3 -2 </option>
</select>
</form>
Upvotes: 2
Reputation: 1074385
Another way is to use event delegation, where you hook click
on an ancestor element that all of these selects are in, and take advantage of the fact that click
bubbles:
document.querySelector("selector-for-the-container").addEventListener("click", function(event) {
const select = event.target.closest(".action");
if (select && this.contains(select)) {
event.currentTarget = select;
return myFunction.call(select, event);
}
});
The update of currentTarget
and calling myFunction
with this
set to the select
make it look like the event was directly attached to the select. You don't have to do that, though, or you could do just one but not the other, it depends on what you want myFunction
to do.
See on MDN:
Upvotes: 2