简体   繁体   中英

forEach can't read new node elements - js

I write a very simple Todo app with JS . It's work fine, I have some default tasks that I can click on them to change them to done or undone, but the problem is when I add a new task, I can't do anything on it.

const input   = document.querySelector('#todoText');
const todo  = document.querySelector('#todo');
const todoLi  = document.querySelectorAll('#todo li');

// Add Todo
input.addEventListener('keyup', e => {
  if (e.keyCode === 13) {
    // Get input value
    let val = e.target.value;
    // Create <li>
    const li = document.createElement('li');
    // Create text node from input value
    let text = document.createTextNode(val);
    // Pass input value into <li>
    li.appendChild(text);
    // Add input value in Todo list
    todo.appendChild(li);
    // Reset input value after enter
    e.target.value = '';
  }
})


todoLi.forEach( item => {
  item.addEventListener('click', e => {

    if ( e.target.classList.contains('done') ) {
      e.target.classList.remove('done')
    } else {
      e.target.classList.add('done')
    }

  })
})

This is my PEN on Codepen

Add

li.addEventListener('click', e => {
  if ( e.target.classList.contains('done') ) {
    e.target.classList.remove('done')
  } else {
    e.target.classList.add('done')
  }
});

After

li.appendChild(text);

To add a click listener on the node before you insert it into the DOM.

Forked and fixed snippet:

 const input = document.querySelector('#todoText'); const todo = document.querySelector('#todo'); const todoLi = document.querySelectorAll('#todo li'); // Add Todo input.addEventListener('keyup', e => { if (e.keyCode === 13) { // Get input value let val = e.target.value; // Create <li> const li = document.createElement('li'); // Create text node from input value let text = document.createTextNode(val); // Pass input value into <li> li.appendChild(text); li.addEventListener('click', e => { if ( e.target.classList.contains('done') ) { e.target.classList.remove('done') } else { e.target.classList.add('done') } }); // Add input value in Todo list todo.appendChild(li); // Reset input value after enter e.target.value = ''; } }) todoLi.forEach( item => { item.addEventListener('click', e => { if ( e.target.classList.contains('done') ) { e.target.classList.remove('done') } else { e.target.classList.add('done') } }) })
 body { margin: 50px; } input { padding: 5px 15px; background: #eee; border: 0; width: 100%; margin-left: 10px; border: solid 2px #eee; border-radius: 50px; transition: all 350ms; font-size: 12px; &:focus { border: solid 2px #eee; background: #fff; outline: none; } } ul { li { position: relative; cursor: pointer; transition: all 350ms; &:hover { &:before { content: '👉'; position: absolute; left: -25px } } } } .done { text-decoration: line-through; color: #888; }
 <div class="d-flex align-items-center mb-5"> <span class="font-weight-bold text-muted">TODO:</span> <input id="todoText" placeholder="Write something and press Enter"> </div> <small>Todo list:</small> <ul id="todo"> <li>Add something new 👽</li> <li>This is a todo app with JS 🦄</li> <li class="done">I'm a done task 👁😍</li> </ul> <hr>

You might solve your problem and simplify your code by adding click event listener to #todo , not to li elements:

 const input = document.querySelector('#todoText'); const todo = document.querySelector('#todo'); // Add Todo input.addEventListener('keyup', e => { if (e.keyCode === 13) { // Get input value let val = e.target.value; // Create <li> const li = document.createElement('li'); // Create text node from input value let text = document.createTextNode(val); // Pass input value into <li> li.appendChild(text); // Add input value in Todo list todo.appendChild(li); // Reset input value after enter e.target.value = ''; } }) todo.addEventListener('click', e => { var li = e.target; while (li.nodeName.toLowerCase() !== 'li') { if (li === this) return; li = li.parentNode; } li.classList.toggle('done') })
 body { margin: 50px; } input { padding: 5px 15px; background: #eee; border: 0; width: 100%; margin-left: 10px; border: solid 2px #eee; border-radius: 50px; transition: all 350ms; font-size: 12px; &:focus { border: solid 2px #eee; background: #fff; outline: none; } } ul { li { position: relative; cursor: pointer; transition: all 350ms; &:hover { &:before { content: '👉'; position: absolute; left: -25px } } } } .done { text-decoration: line-through; color: #888; }
 <div class="d-flex align-items-center mb-5"> <span class="font-weight-bold text-muted">TODO:</span> <input id="todoText" placeholder="Write something and press Enter"> </div> <small>Todo list:</small> <ul id="todo"> <li>Add something new 👽</li> <li>This is a todo app with JS 🦄</li> <li class="done">I'm a done task 👁😍</li> </ul> <hr>

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