'How do you toggle check marks on an HTML unordered list?
var state = 0;
function selectLI(element) {
if (state == 0) {
element.innerHTML = element.innerHTML + "<span class='liTick'>✔</span>";
state = 1;
} else {
var ele = document.getElementsByClassName('checklistLI');
for (var i = 0; i < ele.length; i++) {
var els = ele[i].getElementsByClassName(".liTick");
els.item(0).style.display = "none";
}
}
}
<ul class="checklist">
<li class="checklistLI" onclick="selectLI(this)">item 1</li>
<li class="checklistLI" onclick="selectLI(this)">item 2</li>
</ul>
What the code is supposed to do is remove the ticks generated by the code above. But it doesn't work and keep giving me error - "Uncaught TypeError: Cannot read properties of null (reading 'style')" when I try to remove the first tick and generate second one.
Solution 1:[1]
As @Andy Holmes suggested in a comment:
This seems a lot more complicated for what it's actually doing. Why don't you just put the ticks there by default, and when clicking on the relevant
li
you just toggle a hidden class (which hasdisplay: none;
) on the tick rather than this seemingly excessive code?
HTML
<ul class="checklist">
<li class="checklistLI" onclick="selectLI(this)">item 1 <span class='liTick hidden'>✔</span></li>
<li class="checklistLI" onclick="selectLI(this)">item 2 <span class='liTick hidden'>✔</span></li>
<li class="checklistLI" onclick="selectLI(this)">item 3 <span class='liTick hidden'>✔</span></li>
</ul>
CSS
.hidden {
display: none;
}
JS
function selectLI(element) {
document.querySelectorAll(".checklistLI").forEach(function (el) {
el.getElementsByClassName("liTick").item(0).classList.add("hidden");
});
element.getElementsByClassName("liTick").item(0).classList.remove("hidden");
}
Demo
Solution 2:[2]
There are two issues making it so your code doesn't hide the tick:
You've included a
.
in the class name when callinggetElementsByClassName
, but the class name doesn't actually have a dot in it.You're looping through all the
li
elements, but only some of them have aliTick
inside them; you're not allowing for the possibility you didn't find one.
The minimal fix is:
var els = ele[i].getElementsByClassName("liTick");
// No `.` here ??????????????????????????^
if (els[0]) { // <== Make sure there is one
els[0].style.display = "none";
}
Or in really up-to-date environments, you could use optional chaining:
var els = ele[i].getElementsByClassName("liTick");
els[0]?.style.display = "none";
But, I wouldn't do that, because it's just hiding the tick. The be consistent, if you're adding a tick, you should remove (not just hide) it.
Separately, you have only one state flag, but there are multiple elements. I'm going to assume they should be independently "tick"-able. For that, we want to base our decision on whether the element already has a tick in it.
Also, avoid using innerHTML
(and in particular avoid .innerHTML = .innerHTML + "x"
). Instead, just insert what you need.
Here's an example:
function selectLI(element) {
const tick = element.querySelector(".liTick");
if (tick) {
// Remove the tick
tick.remove(); // In modern environments
// Or: tick.parentNode.removeChild(tick); // In older environments
} else {
// Add the tick
element.insertAdjacentHTML(
"beforeend",
"<span class='liTick'>✔</span>"
);
}
}
<ul class="checklist">
<li class="checklistLI" onclick="selectLI(this)">item 1</li>
<li class="checklistLI" onclick="selectLI(this)">item 2</li>
</ul>
Or if you wanted only one item to be allowed to have a tick:
function selectLI(element) {
const tick = element.querySelector(".liTick");
if (tick) {
// Remove the tick
tick.remove(); // In modern environments
// Or: tick.parentNode.removeChild(tick); // In older environments
} else {
// Remove any other tick
const other = document.querySelector(".checklistLI .liTick");
if (other) {
other.remove(); // Or, again, the longer form in old environments
}
// Add the tick to this element
element.insertAdjacentHTML(
"beforeend",
"<span class='liTick'>✔</span>"
);
}
}
<ul class="checklist">
<li class="checklistLI" onclick="selectLI(this)">item 1</li>
<li class="checklistLI" onclick="selectLI(this)">item 2</li>
</ul>
Note that this is not accessible to people using assistive technologies. Consider using a <input type="checkbox">
instead.
Solution 3:[3]
You can use this solution, it's working!
<ul class="checklist">
<li class="checklistLI" onclick="selectLI(this, 1)">item 1</li>
<li class="checklistLI" onclick="selectLI(this, 2)">item 2</li>
</ul>
<script>
var state1 = 0;
var state2 = 0;
function selectLI(element, flag) {
if (flag === 1) {
if (state1 === 0) {
element.innerHTML = element.innerHTML + "<span class='liTick'>✔</span>";
state1 = 1;
} else {
element.innerHTML = 'item 1';
state1 = 0;
}
} else {
if (state2 === 0) {
element.innerHTML = element.innerHTML + "<span class='liTick'>✔</span>";
state2 = 1;
} else {
element.innerHTML = 'item 2';
state2 = 0;
}
}
}
</script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Ayaz Shaikh |