hendercode
hendercode

Reputation: 11

Javascript click function only selects the first element or all elements at once

I made a simple unordered list with checkboxes and want a class with strikethrough text to be applied to the li that the checkbox belongs to. The methods I've tried either only work on the first element or get applied to all of them at once.

The HTML:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <title>Document</title>
</head>
<body>
  <h1>Todo List</h1>
  <ul>
    <li>
      <input type="checkbox">
      List Item 1
    </li>
    <li>
      <input type="checkbox">
      List Item 2
    </li>
    <li>
      <input type="checkbox">
      List Item 3
    </li>
  </ul>
</body>
</html>

The Javascript (only selects the first one):

document.querySelector("input").addEventListener("click", addStrike);

function addStrike() {
  document.querySelector("li").classList.toggle("completed");
}

(selects all at once, when using this code I had the jquery CDN in my html)

$("li").on("click", addStrike);

function addStrike() {
  $("li").toggleClass("completed")
}

Upvotes: 0

Views: 1751

Answers (3)

Akash
Akash

Reputation: 377

Add an Id to the UL and then use the below javascript

document.getElementById('ele').addEventListener('click',function(e){
    event.target.parentElement.classList.toggle('completed');
});

document.querySelector always returns the first element that matches the given selector

Upvotes: 0

Thiago
Thiago

Reputation: 303

If you would rather apply the class 'completed' (and for that the style) when the check box is checked, I would recommend doing this, with jQuery:

$(".strikeCheckbox").change(function() {
    if(this.checked) {
        $(this).parent().addClass("completed")
    } else {
        $(this).parent().removeClass("completed")
    }
});

You can change the parent function for a specific prev(...) if you want.

Upvotes: 0

epascarello
epascarello

Reputation: 207501

You need to select all the checkboxes, loop over them, and attach the event.

function cbClicked (event) {
  // reference the checkbox
  var cb = event.target
  // find it was checked
  var isChecked = cb.checked
  cb.closest("li")  // find the parent li
    .classList.toggle("done", isChecked) // toggle the class
}


// Select all the checkboxes
var checkboxes = document.querySelectorAll('ul input[type="checkbox"]')

// loop over all the checkboxes
checkboxes.forEach( function (cb) {
  // attach the event listener to each one
  cb.addEventListener("change", cbClicked)
})
.done {
  text-decoration: line-through;
}
<ul>
    <li>
      <input type="checkbox">
      List Item 1
    </li>
    <li>
      <input type="checkbox">
      List Item 2
    </li>
    <li>
      <input type="checkbox">
      List Item 3
    </li>
  </ul>

If you want to use jQuery it is similar, jQuery just does the looping for you

function cbClicked (event) {
  // reference the checkbox
  var cb = this
  var isChecked = this.checked
  $(cb).closest("li")  // find the parent li
    .toggleClass("done", isChecked) // toggle the class
}


// Select all the checkboxes
var checkboxes = $('ul input[type="checkbox"]').on("change", cbClicked)
.done {
  text-decoration: line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
    <li>
      <input type="checkbox">
      List Item 1
    </li>
    <li>
      <input type="checkbox">
      List Item 2
    </li>
    <li>
      <input type="checkbox">
      List Item 3
    </li>
  </ul>

And it can be done with Just CSS

input:checked + label {
  text-decoration: line-through;
}
<ul>
    <li>
      <input type="checkbox" id="cb1">
      <label for="cb1">List Item 1</label>
    </li>
    <li>
      <input type="checkbox" id="c2">
      <label for="cb2">List Item 2</label>
    </li>
    <li>
      <input type="checkbox" id="cb3">
      <label for="cb3">List Item 3</label>
    </li>
  </ul>

Upvotes: 1

Related Questions