简体   繁体   中英

How to add/remove class from a parent List-item(li) when their child checkbox is changed in javascript?

I am building a simple Todo app in Javascript but I got stuck trying to add/remove a class to a List-item(li) that is the parent of a checkbox.

By default a list-item (Todo) checkbox is unchecked (with no class added). Whenever a user check a todo checkbox, a class is added, and the todo text gets a line through.

I managed to make it work but nothing happens.

 // ADD ITEM, REMOVE ITEM - FUNCIONALITY const btn = document.getElementById('btn'); const ulList = document.getElementById('list'); // Button event listener with adding li elemnts with input value btn.addEventListener('click', function() { var input = document.getElementById('input').value; // Capture input value var newItem = document.createElement("LI"); // Create a <li> node newItem.innerHTML = input + '<input type="checkbox" class="checkboxes" ><p class="delet">x</p>'; // Add content to li element for todo. ulList.insertBefore(newItem, ulList.childNodes[0]); // Insert <li> before the first child of <ul> // input = ' '; // Reset input value to empty field // Remove item funcionality newItem.childNodes[2].onclick = function() { this.parentNode.remove(this); } }) // ********** IMPORTANT CODE BELOW *********************** // MARK DONE TODO - FUNCIONALITY var checkBox = document.getElementsByClassName('checkboxes'); for (var i = 0; i < checkBox; i++) { checkBox[i].addEventListener('change', function() { if (this.checked) { // Checkbox is checked.. this.parentNode.classList.add("line-through"); } else { // Checkbox is not checked.. this.parentNode.classList.remove("line-through"); } }); } 
 .line-through { text-decoration: line-through; } 
 <p class="lead text-center">Welcome to my todoList applications</p> <div class="row"> <form id="form" class="col-lg-6 col-8 mx-auto"> <div class="input-group"> <input type="text" id="input" class="form-control"><span> <button id="btn" type="button" class="btn btn-primary">Submit</button></span> </div> </form> </div> <div class="row"> <ul id="list" class="list col-lg-6 col-8 mx-auto"> <!-- <li>this is a todo item <input type="checkbox" class="checkbox"></li> <li>this is a todo item <input type="checkbox" class="checkbox"></li> --> </ul> </div> <div class="row"> <button id="btnClr" type="button" class="btn btn-primary mx-auto btnHide">Clear All Todos</button> </div> 

I would appreciate any help. Thanks in advance everyone! :)

A complete and working example below. Generally speaking, it is easier (for me, but your personal experiences may vary) to utilize document.createElement instead of .innerHTML for tasks like yours, because attaching event listeners to elements created by document.createElement is (again, in my opinion) much easier.

The example creates a new <li> , <input type="checkbox"> , <span> (for the todo's title) and a <button> (for deleting the todo) whenever the "Submit" button is clicked. After all inner elements are created, they are easy to append to the <li> with .appendChild .

I tried to use descriptive names, so following along shouldn't be complicated.

 const todoAddBtn = document.getElementById('btn'); const todoDeleteBtn = document.getElementById('btnClr'); const todosList = document.getElementById('list'); const todoInput = document.getElementById('input'); todoAddBtn.addEventListener('click', function(){ const todoTopic = readAndClearValue(todoInput); const todoLi = createListItem(); const todoCheckbox = createCheckbox(); const todoTitle = createTitle(todoTopic); const todoDelete = createDeleteButton(); todoLi.appendChild(todoCheckbox); todoLi.appendChild(todoTitle); todoLi.appendChild(todoDelete); todosList.insertBefore(todoLi, todosList.firstElementChild); }); todoDeleteBtn.addEventListener('click', function () { todosList.innerHTML = ''; }); // readAndClearValue :: HTMLElement -> String function readAndClearValue (element) { const value = element.value; element.value = ''; return value; } // createListItem :: () -> HTMLElement function createListItem () { return document.createElement('li'); } // createTitle :: String -> HTMLElement function createTitle (text) { const title = document.createElement('span'); title.textContent = text; return title; } // createDeleteButton :: () -> HTMLElement function createDeleteButton () { const button = document.createElement('button'); button.textContent = 'X'; button.className = 'delet'; button.addEventListener('click', function () { button.parentNode.removeChild(button); // to remove the <li>, use something like // button.parentNode.parentNode.removeChild(button.parentNode) // or button.closest('li').remove() if supported }); return button; } // createCheckbox :: () -> HTMLElement function createCheckbox () { const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.className = 'checkboxes'; checkbox.addEventListener('change', function () { if (checkbox.checked) { checkbox.parentNode.classList.add('line-through'); } else { checkbox.parentNode.classList.remove('line-through'); } }); return checkbox; } 
 .line-through { text-decoration: line-through; } 
 <p class="lead text-center">Welcome to my todoList applications</p> <div class="row"> <form id="form" class="col-lg-6 col-8 mx-auto"> <div class="input-group"> <input type="text" id="input" class="form-control" > <button id="btn" type="button" class="btn btn-primary">Submit</button> </div> </form> </div> <div class="row"> <ul id="list" class="list col-lg-6 col-8 mx-auto"> </ul> </div> <div class="row"> <button id="btnClr" type="button" class="btn btn-primary mx-auto btnHide"> Clear All Todos </button> </div> 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <style>
        .line-through li {
            text-decoration: line-through;
        }
    </style>
</head>
<body>
<p class="lead text-center">Welcome to my todoList applications</p>
<div class="row">
    <form id="form" class="col-lg-6 col-8 mx-auto">
        <div class="input-group">
            <input type="text" id="input" class="form-control" ><span>
        <button id="btn" type="button" class="btn btn-primary">Submit</button></span>
        </div>
    </form>
</div>
<div class="row">
    <ul id="list" class="list col-lg-6 col-8 mx-auto">
        <!-- <li>this is a todo item <input type="checkbox" class="checkbox"></li>
              <li>this is a todo item <input type="checkbox" class="checkbox"></li> -->
    </ul>
</div>
<div class="row">
    <button id="btnClr" type="button" class="btn btn-primary mx-auto btnHide">Clear All Todos</button>
</div>
</body>
<script>
    // ADD ITEM, REMOVE ITEM - FUNCIONALITY
    const btn = document.getElementById('btn');
    const ulList = document.getElementById('list');
    let checkBox = document.querySelectorAll('.checkboxes li');


    // Button event listener with adding li elemnts with input value
    btn.addEventListener('click', function(){
        var input = document.getElementById('input').value; // Capture input value
        var newItem = document.createElement("LI");     // Create a <li> node
        newItem.innerHTML = input + '<input type="checkbox" class="checkboxes" ><p class="delet">x</p>';  // Add content to li element for todo.
        ulList.insertBefore(newItem, ulList.childNodes[0]);  // Insert <li> before the first child of <ul>
        // input = ' ';  // Reset input value to empty field

        // Remove item funcionality
        newItem.childNodes[2].onclick = function() {this.parentNode.remove(this);}
    });

    // ********** IMPORTANTO CODE BELOW ***********************
    // MARK DONE TODO  - FUNCIONALITY


    document.body.addEventListener( 'click', function ( event ) {
        if (event.srcElement.className == 'checkboxes') {

                console.log(this);
                this.classList.toggle('line-through');

        }
    });

    checkBox.forEach(el => {
        el.addEventListener('change', myFunction);
    }, false);

    function myFunction(){
        if(this.checked) {
            console.log('here')
            this.classList.toggle('line-through');
        }
    }
</script>
</html>

Seems like you need to add listeners after checkbox creation. Shat's happening now You load the page and at the start, you don't have any checkbox, so when you run for loop no handlers attached

Here is a sniped of how to make it work. There are a lot of changes but I've tried to leave detailed comments.

Feel free to ask if you have any questions :)

https://codesandbox.io/embed/bootstrap-r3ud0

Also here is JS part.

 const btn = document.getElementById("btn"); const ulList = document.getElementById("list"); // Button event listener with adding li elemnts with input value btn.addEventListener("click", function() { var input = document.getElementById("input").value; // Capture input value var newItem = document.createElement("LI"); // Create a <li> node // manually create input element var inputEl = document.createElement("input"); // set attributes inputEl.type = "checkbox"; inputEl.class = "checkboxes"; // also create p element var xmark = document.createElement("p"); xmark.innerHTML = "x"; xmark.class = "delet"; // set click handler xmark.onclick = function() { this.parentNode.remove(this); }; // most important part! // we add change listener on input create step inputEl.addEventListener("change", changeHandler); newItem.innerHTML = input; // and append our new elements to the li newItem.appendChild(inputEl); newItem.appendChild(xmark); ulList.insertBefore(newItem, ulList.childNodes[0]); // Insert <li> before the first child of <ul> }); // create separate handler for change event (first param is event) const changeHandler = event => { // we can access checked property of an element const checked = event.target.checked; // also we need the target (input in this case) for further manipulations const element = event.target; if (checked) { // Checkbox is checked.. element.parentNode.classList.add("line-through"); } else { // Checkbox is not checked.. element.parentNode.classList.remove("line-through"); } }; 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM