Lasha Lashashvili
Lasha Lashashvili

Reputation: 11

Adding eventListener to the newly created element

There are several questions like this but can't find the answer. I'm tring to create some HTML elements after pressing the button and add eventListener to the checkbox right after creating it , but it does nothing. Can't find out what is the reason, it does not return any error.

let addTaskBtn = document.querySelector('.inputPlusSign')
let tasksAreaDiv = document.querySelector('.tasksArea')
let inputText = document.querySelector('#taskInput')

addTaskBtn.addEventListener('click', function() {
  let taskWrapperDiv = document.createElement('div')
  taskWrapperDiv.setAttribute('class', 'taskWrapper')

  let taskDiv = document.createElement('div')
  taskDiv.setAttribute('class', 'task')

  let label = document.createElement('label')
  label.setAttribute('class', 'checkContainer')

  let checkBox = document.createElement('input')
  checkBox.setAttribute('type', 'checkbox')
  checkBox.setAttribute('class', 'taskCheckBox')

  let checkBoxSpan = document.createElement('span')
  checkBoxSpan.setAttribute('class', 'checkmark')

  let taskTextSpan = document.createElement('span')
  taskTextSpan.setAttribute('class', 'taskText')
  taskTextSpan.innerText = inputText.value

  label.appendChild(checkBox)
  label.appendChild(checkBoxSpan)

  taskDiv.appendChild(label)
  taskDiv.appendChild(taskTextSpan)
  taskDiv.innerHTML += `<i class="fa-regular fa-trash-can trashCan"></i>`

  taskWrapperDiv.appendChild(taskDiv)

  tasksAreaDiv.appendChild(taskWrapperDiv)

  checkBox.addEventListener('click', function() {
    console.log('any text')
  })

})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-color: rgb(9, 9, 34);
  color: white;
  font-size: 1.5rem;
}

.main {
  width: 70%;
  margin: auto;
}

.wrapper {
  width: 60%;
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.title {
  padding: 1rem 0;
}

.inputWrapper {
  width: 100%;
  position: relative;
}

#taskInput {
  width: 100%;
  padding: 7px 50px 7px 20px;
  border-radius: 40px;
  font-size: 1.2rem;
  background-color: #dab979;
  border: none;
  caret-color: hsla(196, 43%, 33%, 1);
  color: white;
}

#taskInput:focus {
  outline-offset: 2px;
}

#taskInput::placeholder {
  color: white;
}

.inputPlusSign {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 15px;
  font-weight: bold;
  font-size: 20px;
  color: #fcedd3;
  cursor: pointer;
}

.inputPlusSign:active {
  color: white;
}

.tasksArea {
  width: 95%;
  background-color: hsla(196, 43%, 33%, 0.5);
  min-height: 300px;
  margin-top: 1rem;
  padding-bottom: 2rem;
}

.taskWrapper {
  border-bottom: 1px solid black;
}

.task {
  padding: 1rem 3rem;
  position: relative;
}

.checkContainer {
  user-select: none;
}

.taskCheckBox {
  position: absolute;
  opacity: 0;
  cursor: pointer;
  height: 0;
  width: 0;
}

.checkmark {
  position: absolute;
  top: 50%;
  left: 1rem;
  transform: translateY(-50%);
  height: 20px;
  width: 20px;
  background-color: #dab979;
  box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
}

.checkContainer:hover .taskCheckBox~.checkmark {
  background-color: #fcedd3;
}

.checkContainer .taskCheckBox:checked~.checkmark {
  background-color: #dab979;
}

.checkmark:after {
  content: "";
  position: absolute;
  display: none;
}

.checkContainer .taskCheckBox:checked~.checkmark:after {
  display: block;
}

.checkContainer:has(.taskCheckBox:checked)~.taskText {
  text-decoration: line-through;
}

.checkContainer .checkmark:after {
  left: 6px;
  top: 2px;
  width: 5px;
  height: 10px;
  border: solid #fcedd3;
  border-width: 0 3px 3px 0;
  transform: rotate(45deg);
}

.taskText {
  margin-left: 10px;
}

.trashCan {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 1rem;
  color: #dab979;
  cursor: pointer;
}

.trashCan:hover {
  color: #fcedd3;
}

.taskText {
  overflow-wrap: break-word;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" rel="stylesheet" />
<div class="main">
  <div class="wrapper">
    <h3 class="title">Type your task here . . .</h3>
    <div class="inputWrapper">
      <input type="text" id="taskInput" placeholder="What's your focus for today?">
      <i class="fa-light fa-plus inputPlusSign"></i>
    </div>
    <div class="tasksArea">
    </div>
  </div>
</div>

Upvotes: 0

Views: 48

Answers (2)

Andreas
Andreas

Reputation: 21881

The source of the problem is the switch from .appendChild() to .innerHTML.

taskDiv.innerHTML += `<i class="fa-regular fa-trash-can trashCan"></i>`

After this line the reference in checkBox points to a different <input type="checkbox" /> element, because you've overwritten it.

(checkBox === taskDiv.querySelector('input[type="checkbox"]') // -> false)

Either use .createElement() and .appendChild() or .insertAdjacentHTML() to add the <i> element:

taskDiv.insertAdjacentHTML("beforeend", '<i class="fa-regular fa-trash-can trashCan"></i>');

let addTaskBtn = document.querySelector('.inputPlusSign')
let tasksAreaDiv = document.querySelector('.tasksArea')
let inputText = document.querySelector('#taskInput')

addTaskBtn.addEventListener('click', function() {
  let taskWrapperDiv = document.createElement('div')
  taskWrapperDiv.setAttribute('class', 'taskWrapper')

  let taskDiv = document.createElement('div')
  taskDiv.setAttribute('class', 'task')

  let label = document.createElement('label')
  label.setAttribute('class', 'checkContainer')

  let checkBox = document.createElement('input')
  checkBox.setAttribute('type', 'checkbox')
  checkBox.setAttribute('class', 'taskCheckBox')

  let checkBoxSpan = document.createElement('span')
  checkBoxSpan.setAttribute('class', 'checkmark')

  let taskTextSpan = document.createElement('span')
  taskTextSpan.setAttribute('class', 'taskText')
  taskTextSpan.innerText = inputText.value

  label.appendChild(checkBox)
  label.appendChild(checkBoxSpan)

  taskDiv.appendChild(label)
  taskDiv.appendChild(taskTextSpan)
  taskDiv.insertAdjacentHTML("beforeend", `<i class="fa-regular fa-trash-can trashCan"></i>`);

  taskWrapperDiv.appendChild(taskDiv)

  tasksAreaDiv.appendChild(taskWrapperDiv)

  checkBox.addEventListener('click', function() {
    console.log('any text')
  })

})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-color: rgb(9, 9, 34);
  color: white;
  font-size: 1.5rem;
}

.main {
  width: 70%;
  margin: auto;
}

.wrapper {
  width: 60%;
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.title {
  padding: 1rem 0;
}

.inputWrapper {
  width: 100%;
  position: relative;
}

#taskInput {
  width: 100%;
  padding: 7px 50px 7px 20px;
  border-radius: 40px;
  font-size: 1.2rem;
  background-color: #dab979;
  border: none;
  caret-color: hsla(196, 43%, 33%, 1);
  color: white;
}

#taskInput:focus {
  outline-offset: 2px;
}

#taskInput::placeholder {
  color: white;
}

.inputPlusSign {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 15px;
  font-weight: bold;
  font-size: 20px;
  color: #fcedd3;
  cursor: pointer;
}

.inputPlusSign:active {
  color: white;
}

.tasksArea {
  width: 95%;
  background-color: hsla(196, 43%, 33%, 0.5);
  min-height: 300px;
  margin-top: 1rem;
  padding-bottom: 2rem;
}

.taskWrapper {
  border-bottom: 1px solid black;
}

.task {
  padding: 1rem 3rem;
  position: relative;
}

.checkContainer {
  user-select: none;
}

.taskCheckBox {
  position: absolute;
  opacity: 0;
  cursor: pointer;
  height: 0;
  width: 0;
}

.checkmark {
  position: absolute;
  top: 50%;
  left: 1rem;
  transform: translateY(-50%);
  height: 20px;
  width: 20px;
  background-color: #dab979;
  box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
}

.checkContainer:hover .taskCheckBox~.checkmark {
  background-color: #fcedd3;
}

.checkContainer .taskCheckBox:checked~.checkmark {
  background-color: #dab979;
}

.checkmark:after {
  content: "";
  position: absolute;
  display: none;
}

.checkContainer .taskCheckBox:checked~.checkmark:after {
  display: block;
}

.checkContainer:has(.taskCheckBox:checked)~.taskText {
  text-decoration: line-through;
}

.checkContainer .checkmark:after {
  left: 6px;
  top: 2px;
  width: 5px;
  height: 10px;
  border: solid #fcedd3;
  border-width: 0 3px 3px 0;
  transform: rotate(45deg);
}

.taskText {
  margin-left: 10px;
}

.trashCan {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 1rem;
  color: #dab979;
  cursor: pointer;
}

.trashCan:hover {
  color: #fcedd3;
}

.taskText {
  overflow-wrap: break-word;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" rel="stylesheet" />
<div class="main">
  <div class="wrapper">
    <h3 class="title">Type your task here . . .</h3>
    <div class="inputWrapper">
      <input type="text" id="taskInput" placeholder="What's your focus for today?">
      <i class="fa-light fa-plus inputPlusSign"></i>
    </div>
    <div class="tasksArea">
    </div>
  </div>
</div>

Upvotes: 1

Michael M.
Michael M.

Reputation: 11070

I don't recommend adding a new event listener for each new element. Instead, add an event listener to a parent <div> and use event propagation to listen only to elements that have that checkbox class. Like this:

let addTaskBtn = document.querySelector('.inputPlusSign')
let tasksAreaDiv = document.querySelector('.tasksArea')
let inputText = document.querySelector('#taskInput')

document.querySelector('.tasksArea').addEventListener('click', e => {
  if (!e.target.classList.contains('taskCheckBox')) return;
  const el = e.target;
  console.log(e.target + ' was clicked!');
});

addTaskBtn.addEventListener('click', function() {
  let taskWrapperDiv = document.createElement('div')
  taskWrapperDiv.setAttribute('class', 'taskWrapper')

  let taskDiv = document.createElement('div')
  taskDiv.setAttribute('class', 'task')

  let label = document.createElement('label')
  label.setAttribute('class', 'checkContainer')

  let checkBox = document.createElement('input')
  checkBox.setAttribute('type', 'checkbox')
  checkBox.setAttribute('class', 'taskCheckBox')

  let checkBoxSpan = document.createElement('span')
  checkBoxSpan.setAttribute('class', 'checkmark')

  let taskTextSpan = document.createElement('span')
  taskTextSpan.setAttribute('class', 'taskText')
  taskTextSpan.innerText = inputText.value

  label.appendChild(checkBox)
  label.appendChild(checkBoxSpan)

  taskDiv.appendChild(label)
  taskDiv.appendChild(taskTextSpan)
  taskDiv.innerHTML += `<i class="fa-regular fa-trash-can trashCan"></i>`

  taskWrapperDiv.appendChild(taskDiv)

  tasksAreaDiv.appendChild(taskWrapperDiv)
})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-color: rgb(9, 9, 34);
  color: white;
  font-size: 1.5rem;
}

.main {
  width: 70%;
  margin: auto;
}

.wrapper {
  width: 60%;
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.title {
  padding: 1rem 0;
}

.inputWrapper {
  width: 100%;
  position: relative;
}

#taskInput {
  width: 100%;
  padding: 7px 50px 7px 20px;
  border-radius: 40px;
  font-size: 1.2rem;
  background-color: #dab979;
  border: none;
  caret-color: hsla(196, 43%, 33%, 1);
  color: white;
}

#taskInput:focus {
  outline-offset: 2px;
}

#taskInput::placeholder {
  color: white;
}

.inputPlusSign {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 15px;
  font-weight: bold;
  font-size: 20px;
  color: #fcedd3;
  cursor: pointer;
}

.inputPlusSign:active {
  color: white;
}

.tasksArea {
  width: 95%;
  background-color: hsla(196, 43%, 33%, 0.5);
  min-height: 300px;
  margin-top: 1rem;
  padding-bottom: 2rem;
}

.taskWrapper {
  border-bottom: 1px solid black;
}

.task {
  padding: 1rem 3rem;
  position: relative;
}

.checkContainer {
  user-select: none;
}

.taskCheckBox {
  position: absolute;
  opacity: 0;
  cursor: pointer;
  height: 0;
  width: 0;
}

.checkmark {
  position: absolute;
  top: 50%;
  left: 1rem;
  transform: translateY(-50%);
  height: 20px;
  width: 20px;
  background-color: #dab979;
  box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
}

.checkContainer:hover .taskCheckBox~.checkmark {
  background-color: #fcedd3;
}

.checkContainer .taskCheckBox:checked~.checkmark {
  background-color: #dab979;
}

.checkmark:after {
  content: "";
  position: absolute;
  display: none;
}

.checkContainer .taskCheckBox:checked~.checkmark:after {
  display: block;
}

.checkContainer:has(.taskCheckBox:checked)~.taskText {
  text-decoration: line-through;
}

.checkContainer .checkmark:after {
  left: 6px;
  top: 2px;
  width: 5px;
  height: 10px;
  border: solid #fcedd3;
  border-width: 0 3px 3px 0;
  transform: rotate(45deg);
}

.taskText {
  margin-left: 10px;
}

.trashCan {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 1rem;
  color: #dab979;
  cursor: pointer;
}

.trashCan:hover {
  color: #fcedd3;
}

.taskText {
  overflow-wrap: break-word;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" rel="stylesheet" />
<div class="main">
  <div class="wrapper">
    <h3 class="title">Type your task here . . .</h3>
    <div class="inputWrapper">
      <input type="text" id="taskInput" placeholder="What's your focus for today?">
      <i class="fa-light fa-plus inputPlusSign"></i>
    </div>
    <div class="tasksArea">
    </div>
  </div>
</div>

Upvotes: 1

Related Questions