I have this code, it's about disabling and enabling a button of a form according to its check box input. It's getting executed on different pages, you can see the last two lines where I loop through the forms on the page, all works fine when there is one from in the page, however, on pages where there is more than one form, it doesn't matter which check box I check (second or third for instance) it always affects the first button.
you can notice there are two "console.log" statements, the first one returns the correct input element (so when there are two forms in the pages, you can see in the console the elements reference the correct inputs on the DOM), however, the second one always shows an element in the console referring to the first input in the DOM.
my guess is that there is something wrong with the way I add the event listener, any suggestions for making that work?
class Steps {
constructor(el) {
this.el = el;
this.bindDOM();
this.bindStepEvents();
}
bindDOM() {
this.checkboxSelectorStep = this.el.querySelector('.radio-selector-steps-enable');
this.submit = this.el.querySelector('button[type=submit]');
}
bindStepEvents() {
console.log(this.checkboxSelectorStep); // returns the correct element
this.checkboxSelectorStep.addEventListener('click', (ev) => {
console.log(this.checkboxSelectorStep); // always returns the first element
if (ev.target.checked) {
this.submit.removeAttribute('disabled');
} else {
this.submit.setAttribute('disabled', '');
}
});
}
}
const forms = Array.from(document.querySelectorAll('.radio-selector-steps-form'));
forms.map(form => new Steps(form));
<form method="get" class="radio-selector-steps-form">
<input type="checkbox"
name="checkbox-selector-step"
id="checkbox-selector-step"
class="radio-selector-steps-enable">
<label for="checkbox-selector-step"><span>some text</span></label>
<button type="submit" disabled="">button text</button>
</form>
<form method="get" class="radio-selector-steps-form">
<input type="checkbox"
name="checkbox-selector-step"
id="checkbox-selector-step"
class="radio-selector-steps-enable">
<label for="checkbox-selector-step"><span>some text</span></label>
<button type="submit" disabled="">button text</button>
</form>
The problem was that both of the inputs had the same id, and the labels are referencing that id, so hitting the input itself works fine but whenever the label is being clicked the first listener gets called.
(due to styling, clicking the input was not possible for my case so I would always end up with the wrong behavior until I tried to create a SO snippet for it and caught the issue)
Hoping this might help someone.
You need to use querySelectorAll instead of querySelector
bindDOM() {
this.checkboxSelectorStep = this.el.querySelectorAll(STEPS_ENABLE_CHKBOX);
this.submit = this.el.querySelector(STEPS_FORM_SUBMIT);
}
bindStepEvents() {
console.log(this.checkboxSelectorStep);
this.checkboxSelectorStep.forEach(function(elem) {
elem.addEventListener('click', (ev) => {
console.log(this.checkboxSelectorStep);
if (ev.target.checked) {
this.submit.removeAttribute('disabled');
this.update(JSON.parse(this.steps[0].primaryInput.value))
} else {
this.submit.setAttribute('disabled', '');
}
});
});