The error is telling you that element
is null
, because getElementById
returned null
. The only reason getElementById
returns null
is that no element with that id
exists (see this question's answers).
But just that isn't the root of the problem. You're using a click handler on a div
element (from the error message), then using event.target.id
to find the input
element using getElementById
. There are two problems there:
If event.target.id
were the correct ID, you'd already have the element: event.target
.
It's entirely possible to click somewhere in the div
that isn't the input
element. event.target
is the element that was clicked (in your case, that might be the div
, the label
, or the input
itself). I suspect that's what's happening, you're clicking an element (a label
, for instance) that doesn't have an id
, so you're passing undefined
into getElemntById
, so it's looking for id="undefined"
and not finding it.
Instead, given the structure of your HTML, you should look for the input
within the div
using querySelector
:
const div = event.currentTarget;
const checkbox = div.querySelector("input[type=checkbox]");
Also note that if (element.checked === true)
is more idiomatically written as simply if (element.checked)
.
So doing all of the above:
function sickness_selection() {
const div = event.currentTarget;
const checkbox = div.querySelector("input[type=checkbox]");
// assert(checkbox !== null);
const label = checkbox.parentElement;
if (checkbox.checked) {
label.classList.add("asanism-selected-radio");
} else {
label.classList.remove("asanism-selected-radio");
}
}
If you don't need to support Internet Explorer, you could use the second argument to classList.toggle
instead:
function sickness_selection() {
const div = event.currentTarget;
const checkbox = div.querySelector("input[type=checkbox]");
// assert(checkbox !== null);
const label = checkbox.parentElement;
label.classList.toggle("asanism-selected-radio", checkbox.checked);
}
The above assumes that the handler function is hooked on the div
that's immediately around the checkbox (again, this is an asumption I'm making from the error message). But in a comment you've asked how to handle multiple checkboxes, which suggests to me it may be on a div
deeper in the document that contains multiple copies of the structure you've shown.
If so, the code above won't work (it'll always find the first input[type=checkbox]
in that outer div
). Instead, starting from the target
, find that inner div
to start with (see the ***
line):
function sickness_selection() {
const div = event.target.closest("div"); // ***
const checkbox = div.querySelector("input[type=checkbox]");
// assert(checkbox !== null);
const label = checkbox.parentElement;
label.classList.toggle("asanism-selected-radio", checkbox.checked);
}
Internet Explorer doesn't have that closest
method. You can probably find a polyfill for it. Or just replace it with a loop:
// If you really need IE support
function sickness_selection() {
let div = event.target;
while (div && !div.matches("div")) {
div = div.parentElement;
}
// assert(div !== null);
const checkbox = div.querySelector("input[type=checkbox]");
// assert(checkbox !== null);
const label = checkbox.parentElement;
if (checkbox.checked) {
label.classList.add("asanism-selected-radio");
} else {
label.classList.remove("asanism-selected-radio");
}
}
Finally: It looks like your HTML has a label
within a label
. That's invalid HTML:
label
...
Content model:
Phrasing content, but with no descendant labelable elements unless it is the element's labeled control, and no descendant label
elements.
(my emphasis)