Home > Software design >  classList.toggle() behaves strange
classList.toggle() behaves strange

Time:12-24

I am trying to learn Javascript by creating this very simple todo app. I can type some value in input. When pressed enter or submit button, the value from input tag is added to the ul as a list. Then a class 'list-item' is added to that li tag.

My issue is: I want to cross any individual list when clicked. I have used following code for that. I have the 'cross' style in my CSS, but the problem is that my code does not cross every individual list. It crosses every-other one. I tried forEach as well and the result is same.

const listItems = document.querySelectorAll('list-item');

for (let i=0; i<listItems.length; i  ) {
    
    listItems[i].addEventListener('click', function() {
        console.log(listItems[i])
        listItems[i].classList.toggle('cross');
    })
}

my whole javascript :

const input = document.getElementById('main-input')
const submit = document.getElementById('submit')
const ul = document.getElementById('to_dos');
const del = document.getElementById('del')

//clicking submit button
submit.addEventListener('click', function() {
    addList()
})

//pressing enter key
input.addEventListener("keypress", function(event) {
    if(event.keyCode === 13) {
        event.preventDefault()
        addList()
        
    }
})

//add new todo in the list from input
const addList = () => {
    const newToDo = document.createElement('LI')
    newToDo.classList.add('list-item')
    newToDo.appendChild(document.createTextNode(input.value))
        
        
    ul.appendChild(newToDo)
    input.value = "" 
    
    //cross the completed tasks
    const listItems = document.querySelectorAll('li.list-item');
    
    for (let i=0; i<listItems.length; i  ) {
        
        listItems[i].addEventListener('click', function() {
            console.log(listItems[i])
            listItems[i].classList.toggle('cross');
        })
    }


    //delete button
    del.addEventListener('click', function() {
        const completedItems = document.querySelectorAll('.cross');
        completedItems.forEach(
            completedItem => {
                completedItem.classList.add('hide')
            }
        )
    })
}

CodePudding user response:

Not sure, but a better way to reference the item being clicked is through the event argument that EventListeners generate. You can access the element with event.target. Example:

document.querySelectorAll('li').forEach(li => li.addEventListener('click', e => {
  e.target.classList.toggle('cross');
}))
.cross {
  text-decoration: line-through;
  color:red;
}
<ul>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>

CodePudding user response:

you just forget to add dot (.) at the beggining of the querySelectorAll method. in your case you told querySelectorAll method to find all list-item tag so that dot will change the meaning to find all list-item class. and querySelectorAll will return HTMLCollection not Array so the forEach method will not work you should return it to a Array using Array() function or the following way.

[...document.querySelectorAll('.list-item')]
.forEach(function(element){
    element.addEventListener("click", function(){
        element.classList.toggle("cross")
})
})
  • Related