Prashant Rayamajhi
Prashant Rayamajhi

Reputation: 3

I am having problem with 'done' button's click event on my todo app

I want to create a simple todo list from javascript. Everything seems fine but the functionality is not working properly. I used for loop to iterate through every buttons in the list and fired an event listener on click. The problem is, when there are more than to items on the list and if I click 'done' on the first element the required class i.e. 'line' is not triggered. However, the lists at the bottom seems to be functioning properly.

const add = document.getElementById('add');
let list = document.querySelector('#list');
let task = document.getElementById('task');

// function to handle buttons

function handleButtons(){
    let allSpan = document.querySelectorAll('span');
    let allList = document.querySelectorAll('li');
    const doneButton = document.querySelectorAll('.done');
    const deleteButton = document.querySelectorAll('.delete');

    for(let i=0; i < doneButton.length; i++ ){
            doneButton[i].addEventListener('click',function doneTask(){
            let clickedbtn = [...allSpan].indexOf(doneButton[i].parentElement);
            allList[clickedbtn].firstChild.classList.toggle('line');  

            })  
        }
            
    for(let i=0; i < deleteButton.length; i++ ){
        deleteButton[i].addEventListener('click',function deleteTask(){
                let clickedbtn = [...allSpan].indexOf(deleteButton[i].parentElement);     
                allList[clickedbtn].classList.add('hide');
          
        })
    }
        
}
// Add Lists
function addList(){
    if(task.value !== ''){
    let li = document.createElement('li');
    let p =document.createElement('p')
    p.classList.add('default')
    let t = document.createTextNode(task.value);
    p.appendChild(t);
    // create a span for the buttons
    let span = document.createElement('span');
    let doneBtn = document.createElement('button');
    let doneTxt = document.createTextNode('Done');
    let deleteBtn = document.createElement('button');
    let deleteTxt = document.createTextNode('Delete');
    
    doneBtn.appendChild(doneTxt);
    doneBtn.classList.add('done');
    deleteBtn.appendChild(deleteTxt);
    deleteBtn.classList.add('delete');

    li.appendChild(p);
    span.appendChild(doneBtn);
    span.appendChild(deleteBtn);
    li.appendChild(span);
    list.appendChild(li);
    // console.log(list)
    // reset the input 
    task.value = '';
    }
    else{
        alert('Enter a task!')
    }
    handleButtons();
}
// Event Listeners
add.addEventListener('click',addList);
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'Poppins', sans-serif;
}
ul{list-style: none;}
.main{
    min-height: 100vh;
    padding-top: 100px;
    background-color: rgb(231, 231, 230);
}
.container{
    position: relative;
    text-align: center;
    top: 10%;
    transform: translateY(-10%);
    width: 100%;
    margin: auto;
}
.container h1{
    margin-bottom: 20px;
    font-size: 2.7rem;
    text-transform: uppercase;
    letter-spacing: 5px;
    word-spacing: 5px;
    color: rgb(231, 96, 96);
}
.container input{
    border: none;
    font-size: 1.5rem;
    padding: 4px 8px;
    border-radius: 4px;
    width: 50%;
    outline: none;
}

.container button{
    font-size: 1.5rem;
    border: none;
    cursor: pointer;
    padding: 3px 8px;
    width: 20%;
    background-color: rgb(159, 221, 65);
    transition: .5s;
    outline: none;
}
.container button:hover{
    background-color: rgb(13, 177, 21);
    color: rgb(233, 225, 225);
}
.list{
    margin-top: 20px;
    width: 72%;
    margin: auto;
    padding: 30px 10px;
    font-size: 18px;
    text-align: start;
}
.list li{
    display: flex;
    font-size: 21px;
    margin-bottom: 20px;
    padding: 14px 20px;
    background-color: lightgrey;
    justify-content: space-between;
    align-items: center;

}
#list li span{
    width: 40%;
}
.list .delete{
    background-color: rgb(231, 63, 63);
    width: 40%;
    margin: 10px;
    font-size: 18px;
}
.list .delete:hover{
    background-color: rgb(230, 28, 28);

}
.list .done{
    background-color: rgb(12, 185, 113);
    width: 40%;
    margin: 10px;
    font-size: 18px;
}
.list .done:hover{
    background-color: rgb(5, 168, 59);

}
.default{
    text-decoration:none;
}
p.line{
    text-decoration: line-through;
}
li.hide{
    display: none;
}

@media(max-width:790px){
    #task{
        font-size: 14px;
        width: 67%;
    }
    #add{
        font-size: 14px;
    }
    .list span{
        width: 50%;
        display: flex;
        justify-content: space-around;
    }
    .list{
        width: 95%;
    }
    .list li{
        font-size: 10px;
    }
    .list .done{
        width: 78%;
        font-size: 10px;
    }
    .list .delete{
        
        width: 78%;
        font-size: 10px;
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
    <link href="style.css" rel="stylesheet">
    <title>TODO</title>
</head>
<body>
    <div class="main">
        <div class="container">
            <h1>TODO List</h1>
            <input type="text" name="task" id="task" autocomplete="off" placeholder="Enter The Task">
            <button id="add">ADD</button>

            <div class="list">
                <ul id="list">
                    
                </ul>
            </div>
        </div>
    </div>
<script src="app.js"></script>
</body>
</html>

so

Upvotes: 0

Views: 248

Answers (1)

jrh
jrh

Reputation: 764

@Prashanth,

Please see the quick answer to this problem. I have modified the app.js below. I removed handlebutton function.

const add = document.getElementById('add');
let list = document.querySelector('#list');
let task = document.getElementById('task');

// Add Lists
function addList(){
if(task.value !== ''){
let li = document.createElement('li');
let p =document.createElement('p')
p.classList.add('default')
let t = document.createTextNode(task.value);
p.appendChild(t);
// create a span for the buttons
let span = document.createElement('span');
let doneBtn = document.createElement('button');
let doneTxt = document.createTextNode('Done');
let deleteBtn = document.createElement('button');
let deleteTxt = document.createTextNode('Delete');

doneBtn.addEventListener('click',function(){
    p.classList.toggle('line');
});

deleteBtn.addEventListener('click',function(){    
    li.classList.add('hide');
});
doneBtn.appendChild(doneTxt);
doneBtn.classList.add('done');
deleteBtn.appendChild(deleteTxt);
deleteBtn.classList.add('delete');

li.appendChild(p);
span.appendChild(doneBtn);
span.appendChild(deleteBtn);
li.appendChild(span);
list.appendChild(li);
// console.log(list)
// reset the input 
task.value = '';
}
else{
    alert('Enter a task!')
}
}
// Event Listeners
add.addEventListener('click',addList);

Issue is the on click event was triggering for all buttons for a single click. For assigning onclick for new items, you are iterating complete elements, which is not a good practice.

Upvotes: 2

Related Questions