mary
mary

Reputation: 72

when I click on a element returns multiple times

this is my code(without css file):

var taskInput = document.getElementById("taskInput"),
  taskList = document.getElementById("taskList");

taskList.addEventListener("click", changesLi);

function addTask() {
  if (!taskInput.value) return alert("Please enter a task.");

  var li = createLi(taskInput.value);
  taskList.prepend(li);
  taskInput.value = "";
}

function createLi(title) {
  var li = document.createElement("li"),
    span = document.createElement("span"),
    div = document.createElement("div"),
    remove = document.createElement("a"),
    done = document.createElement("a"),
    doneImg = document.createElement("img"),
    removeImg = document.createElement("img");

  span.textContent = title;
  li.className = "task";
  div.className = "links";
  done.href = "#";
  done.className = "done";
  doneImg.alt = "done";
  done.appendChild(doneImg);
  remove.href = "#";
  remove.className = "remove";
  removeImg.alt = "remove";
  remove.appendChild(removeImg);
  li.appendChild(span);
  li.appendChild(div);
  div.appendChild(done);
  div.appendChild(remove);

  return li;
}

function changesLi(e) {
  if (e.target.parentElement.classList.contains("remove")) {
    e.target.parentElement.parentElement.parentElement.remove();
  }

  if (e.target.parentElement.classList.contains("done")) {
    const tasks = document.querySelectorAll(".done");
    tasks.forEach(task => {
      task.addEventListener("click", function() {
        console.log(e.target);
      });
    });
  }
}
<form class="task-form" onsubmit="event.preventDefault();addTask()">
  <input id="taskInput" placeholder="New task..." autocomplete="off" />
  <input type="submit" value="Add Task" class="submit" />
</form>
<ul id="taskList"></ul>

When I click on a button that contains the done class, the e.target value returns to me as an array each time. The first time I click, nothing returns. The second time, it returns the target once, the third time, the target twice, and so on... No matter how much I searched, I didn't get any results. Where is my problem?

Upvotes: 0

Views: 512

Answers (2)

Barmar
Barmar

Reputation: 780798

Whenever the user clicks on a done button, you're adding a click listener to all the done buttons. Adding a listener doesn't replace previous listeners, so each time they click it adds another listener. When they click again, it runs all the listeners that do the console.log(e.target), as well as the original listener that adds another listener to all the buttons.

You should just log what you want in the original listener, without adding any additional listeners.

var taskInput = document.getElementById("taskInput"),
  taskList = document.getElementById("taskList");

taskList.addEventListener("click", changesLi);

function changesLi(e) {
  if (e.target.parentElement.classList.contains("remove")) {
    e.target.parentElement.parentElement.parentElement.remove();
  } else if (e.target.parentElement.classList.contains("done")) {
    console.log(e.target.parentElement.parentElement.parentElement.querySelector("span").textContent);
  }
}

function addTask() {
  if (!taskInput.value) return alert("Please enter a task.");

  var li = createLi(taskInput.value);
  taskList.prepend(li);
  taskInput.value = "";
}

function createLi(title) {
  var li = document.createElement("li"),
    span = document.createElement("span"),
    div = document.createElement("div"),
    remove = document.createElement("a"),
    done = document.createElement("a"),
    doneImg = document.createElement("img"),
    removeImg = document.createElement("img");

  span.textContent = title;
  li.className = "task";
  div.className = "links";
  done.href = "#";
  done.className = "done";
  doneImg.alt = "done";
  done.appendChild(doneImg);
  remove.href = "#";
  remove.className = "remove";
  removeImg.alt = "remove";
  remove.appendChild(removeImg);
  li.appendChild(span);
  li.appendChild(div);
  div.appendChild(done);
  div.appendChild(remove);

  return li;
}
<form class="task-form" onsubmit="event.preventDefault();addTask()">
  <input id="taskInput" placeholder="New task..." autocomplete="off" />
  <input type="submit" value="Add Task" class="submit" />
</form>
<ul id="taskList"></ul>

Upvotes: 1

Juan Elfers
Juan Elfers

Reputation: 780

Each time you click a '.done' element, you are binding a new click event to each '.done' element:

  if (e.target.parentElement.classList.contains("done")) {
    const tasks = document.querySelectorAll(".done");
    
    // for each '.done'
    tasks.forEach(task => {
      // add another callback for the click event
      task.addEventListener("click", function() {
        console.log(e.target);
      });
    });
  }

And you don't need to do that. Just log the target:

  if (e.target.parentElement.classList.contains("done")) {
    console.log(e.target);
  }

Upvotes: 0

Related Questions