简体   繁体   中英

A simple todoApp checkbox issue

I have a simple todoApp about DOM manipulation.

 const classNames = { TODO_ITEM: 'todo-container', TODO_CHECKBOX: 'todo-checkbox', TODO_TEXT: 'todo-text', TODO_DELETE: 'todo-delete', } const list = document.getElementById('todo-list') const itemCountSpan = document.getElementById('item-count') const uncheckedCountSpan = document.getElementById('unchecked-count') let count = 0; let checkedCount = 0; let todo; function newTodo() { todo = prompt("Please enter to do task","enter here") count++; const markup = `<li><input type="checkbox" id=${todo} name="feature" value=${todo} data-ischecked = "false" /> <label for=${todo}>${todo}</label></li>` list.insertAdjacentHTML("beforeend",markup) itemCountSpan.innerHTML = count; document.getElementById(todo).addEventListener("click",check); } function check(){ let article = document.getElementById(todo); if(article.dataset.ischecked == "false"){ article.dataset.ischecked = "true"; checkedCount++; uncheckedCountSpan.innerHTML = checkedCount } else{ article.dataset.ischecked = "false"; checkedCount--; uncheckedCountSpan.innerHTML = checkedCount } } 
 <!DOCTYPE html> <html> <head> <title>TODO App</title> <link rel="stylesheet" type="text/css" href="./styles.css" /> </head> <body> <div class="container center"> <h1 class="center title">My TODO App</h1> <div class="flow-right controls"> <span>Item count: <span id="item-count">0</span></span> <span>Unchecked count: <span id="unchecked-count">0</span></span> </div> <button class="button center" onClick="newTodo()">New TODO</button> <ul id="todo-list" class="todo-list"></ul> </div> <script src="./script.js"></script> </body> </html> 

However, the checked feature is not what I expected. When I click on the checkbox, the total value should increase/decrease accordingly, but the number is toggling between 0 and 1.

What is the way to fix this? thank you

Why Yours Is Not Working

You're storing the most recently added item's ID as a variable called todo . That means in your check() function, the line...

let article = document.getElementById(todo); 

...will always refer to the last item added . It's just toggling the data-ischecked back and forth on whichever the last item is.


How To Fix It

You want the click event to refer to the checkbox that's being clicked . We can do this by adding a parameter to the check() function, called event . With this, event.target will allow us to refer to the element that's been clicked.

function check(event) {
    let article = event.target; //This is the clicked checkbox!
}

(Given this, the todo variable no longer needs to be global.)


One Other Important Note

I'd highly advise against using todo as the element ID, because your ID cannot have spaces in it. Any time a to-do is entered with a space, your current code will throw an error.

Given that you're not allowing the removal of items, you could set it to something like "todo-" + count so that your IDs would be todo-0 , todo-1 , todo-2 , etc.

I've implemented this in the code below as well, allowing you to add spaces in your to-do items.

 const classNames = { TODO_ITEM: 'todo-container', TODO_CHECKBOX: 'todo-checkbox', TODO_TEXT: 'todo-text', TODO_DELETE: 'todo-delete', } const list = document.getElementById('todo-list') const itemCountSpan = document.getElementById('item-count') const uncheckedCountSpan = document.getElementById('unchecked-count') let count = 0; let checkedCount = 0; function newTodo() { var todo = prompt("Please enter to do task", "enter here"); var newId = "todo" + count; count++; const markup = `<li><input type="checkbox" id=${newId} name="feature" value=${todo} data-ischecked = "false" /> <label for=${todo}>${todo}</label></li>` list.insertAdjacentHTML("beforeend", markup) itemCountSpan.innerHTML = count; document.getElementById(newId).addEventListener("click", check); } function check(event) { let article = event.target; if (article.dataset.ischecked == "false") { article.dataset.ischecked = "true"; checkedCount++; uncheckedCountSpan.innerHTML = checkedCount } else { article.dataset.ischecked = "false"; checkedCount--; uncheckedCountSpan.innerHTML = checkedCount } } 
 <!DOCTYPE html> <html> <head> <title>TODO App</title> <link rel="stylesheet" type="text/css" href="./styles.css" /> </head> <body> <div class="container center"> <h1 class="center title">My TODO App</h1> <div class="flow-right controls"> <span>Item count: <span id="item-count">0</span></span> <span>Unchecked count: <span id="unchecked-count">0</span></span> </div> <button class="button center" onClick="newTodo()">New TODO</button> <ul id="todo-list" class="todo-list"></ul> </div> <script src="./script.js"></script> </body> </html> 


Yo need to pass a reference to the checked element. Something like this:

...
function check(evt){
    let article = document.getElementById(evt.target.id);
...
}

Then yor snippet will work:

 const classNames = { TODO_ITEM: 'todo-container', TODO_CHECKBOX: 'todo-checkbox', TODO_TEXT: 'todo-text', TODO_DELETE: 'todo-delete', } const list = document.getElementById('todo-list') const itemCountSpan = document.getElementById('item-count') const uncheckedCountSpan = document.getElementById('unchecked-count') let count = 0; let checkedCount = 0; let todo; function newTodo() { todo = prompt("Please enter to do task","enter here") count++; const markup = `<li><input type="checkbox" id=${todo} name="feature" value=${todo} data-ischecked = "false" /> <label for=${todo}>${todo}</label></li>` list.insertAdjacentHTML("beforeend",markup) itemCountSpan.innerHTML = count; document.getElementById(todo).addEventListener("click",check); } function check(evt){ let article = document.getElementById(evt.target.id); if(article.dataset.ischecked == "false"){ article.dataset.ischecked = "true"; checkedCount++; uncheckedCountSpan.innerHTML = checkedCount } else{ article.dataset.ischecked = "false"; checkedCount--; uncheckedCountSpan.innerHTML = checkedCount } } 
 <!DOCTYPE html> <html> <head> <title>TODO App</title> <link rel="stylesheet" type="text/css" href="./styles.css" /> </head> <body> <div class="container center"> <h1 class="center title">My TODO App</h1> <div class="flow-right controls"> <span>Item count: <span id="item-count">0</span></span> <span>Unchecked count: <span id="unchecked-count">0</span></span> </div> <button class="button center" onClick="newTodo()">New TODO</button> <ul id="todo-list" class="todo-list"></ul> </div> <script src="./script.js"></script> </body> </html> 

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