Home > Back-end >  addEventListner is not being assigned inside for loop (JS)
addEventListner is not being assigned inside for loop (JS)

Time:11-20

I am trying to create a to do list, for a long while now. I can input a task by typing it in the input and then pressing . However, when I create the new button, I assign it a eventListener, yet the button does not work when it is pressed.

I thought that the problem was that the code for eventListener function was in a outside function and was being 'summoned' yet that was not the case because it still didn't work.

I am planning to make the close function along the lines of this.parentElement.remove() but I first need to be able to get a simple console.log() working for the button before anything else.

const input = document.getElementById("input")
const addBtn = document.getElementById("add")
addBtn.addEventListener('click', function(){addTask()})

const todoList = document.getElementById("todo-list")

let task = document.querySelectorAll('.task')
let closeBtn = document.querySelectorAll('.close')

let taskArray = []

function addTask () {
    taskArray.push(input.value)
    input.value = ""
    renderTasks()
}

function renderTasks() {
    let taskList = ""
    for (let i = 0; i < taskArray.length; i  ){
        let newTask = document.createElement('li')
        newTask.classList.add('task')

        let newP = document.createElement('p')
        newP.textContent = taskArray[i]

        let newClose = document.createElement('button')
        newClose.classList.add('close')
        newClose.textContent = 'x'
        newClose.addEventListener('click', function(){close()})

        newTask.append(newP, newClose)

        taskList  = newTask.outerHTML
    }
    todoList.innerHTML = taskList

    task = document.querySelectorAll('.task')
    closeBtn = document.querySelectorAll('.close')
}

function check() {
    console.log('check()')
}

function close() {
    console.log('close()')
}
.task {
    width: 200px;
    height: 40px;

    display: flex;
    justify-content: space space-between;
    align-items: center;
    flex-direction: row;
}

.task p {
    width: 70%;
}

.close {
    display: inline-block;

    width: 30px;
    height: 30px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <link rel="stylesheet" href="/css/to-do.css">

  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Todo</title>
</head>
<body>
  <div >
    <input type="text" id="input" placeholder="type here">
    <button id="add"> </button>
  </div>
  <div id="todo-wrp">
    <ul id="todo-list">

    </ul>
  </div>

  <script src="/javascript/to-do-list.js"></script>
</body>
</html>

CodePudding user response:

Because you're adding dynamic elements, you can assign a delegate listener - where you place a listener on a static object, and then test that listener for the click you're looking for, like...

todoList.addEventListener('click', e => {
  if (e.target.classList.contains('close')) close(e.target)
})

Then for your delete (close) function, you can use element.closest() to reference the container and just element.remove() it. closest() is better than parentElement as it protects you against certain future html structure changes

Event delegation: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation

Element.closest: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

const input = document.getElementById("input")
const addBtn = document.getElementById("add")
addBtn.addEventListener('click', function() {
  addTask()
})



const todoList = document.getElementById("todo-list")

todoList.addEventListener('click', e => {
  if (e.target.classList.contains('close')) close(e.target)
})

let task = document.querySelectorAll('.task')
let closeBtn = document.querySelectorAll('.close')

let taskArray = []

function addTask() {
  taskArray.push(input.value)
  input.value = ""
  renderTasks()
}

function renderTasks() {
  let taskList = ""
  for (let i = 0; i < taskArray.length; i  ) {
    let newTask = document.createElement('li')
    newTask.classList.add('task')

    let newP = document.createElement('p')
    newP.textContent = taskArray[i]

    let newClose = document.createElement('button')
    newClose.classList.add('close')
    newClose.textContent = 'x'


    newTask.append(newP, newClose)

    taskList  = newTask.outerHTML
  }
  todoList.innerHTML = taskList

  task = document.querySelectorAll('.task')
}

function check() {
  console.log('check()')
}

function close(btn) {
  btn.closest('.task').remove()
}
.task {
  width: 200px;
  height: 40px;
  display: flex;
  justify-content: space space-between;
  align-items: center;
  flex-direction: row;
}

.task p {
  width: 70%;
}

.close {
  display: inline-block;
  width: 30px;
  height: 30px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <link rel="stylesheet" href="/css/to-do.css">

  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Todo</title>
</head>

<body>
  <div >
    <input type="text" id="input" placeholder="type here">
    <button id="add"> </button>
  </div>
  <div id="todo-wrp">
    <ul id="todo-list">

    </ul>
  </div>

  <script src="/javascript/to-do-list.js"></script>
</body>

</html>

  • Related