How do I get event listeners to work on elements rendered with JavaScript

I am trying to create a to-do list application where you can delete and edit tasks. I am working out the delete tasks function. It is not working however. I tried doing a simple task such as logging to the console when the button is clicked, but it won't even respond to that. This seems only to be happening to the
<li>
<li>
elements rendered with JavaScript. Here is my html code Discord is saying my message is too long. So here is the code pen since I can't post the html here https://codepen.io/KhumboMunsaka/pen/gOQQMMd Here is my JavaScript code
const form = document.getElementById('taskForm');
const taskInput = document.querySelector('.task-input');
const dueDateInput = document.querySelector('.due-date');
const taskBar = document.querySelector('.task-bar');
const editButton = document.querySelectorAll('.edit');
const editForm = document.getElementById('taskForm-edit');
const deleteTask = document.querySelectorAll('.delete');

form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent default form submission
let taskDescription = taskInput.value;

const task = `
<li class="task">
<div class="details">
<input type="checkbox" name="" id="" />
<p>${taskDescription}</p>
</div>
<div class="buttons">
<button><i class="fa-solid fa-pen-to-square edit"></i></button>
<button class="delete">❌</button>
</div>
</li>`;
taskBar.insertAdjacentHTML('beforebegin', task);


});

deleteTask.forEach((task) => {
task.addEventListener('click', (e) => {
console.log('hi');
});
});
});
const form = document.getElementById('taskForm');
const taskInput = document.querySelector('.task-input');
const dueDateInput = document.querySelector('.due-date');
const taskBar = document.querySelector('.task-bar');
const editButton = document.querySelectorAll('.edit');
const editForm = document.getElementById('taskForm-edit');
const deleteTask = document.querySelectorAll('.delete');

form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent default form submission
let taskDescription = taskInput.value;

const task = `
<li class="task">
<div class="details">
<input type="checkbox" name="" id="" />
<p>${taskDescription}</p>
</div>
<div class="buttons">
<button><i class="fa-solid fa-pen-to-square edit"></i></button>
<button class="delete">❌</button>
</div>
</li>`;
taskBar.insertAdjacentHTML('beforebegin', task);


});

deleteTask.forEach((task) => {
task.addEventListener('click', (e) => {
console.log('hi');
});
});
});
Feel free to give any feedback on the
4 Replies
Jochem
Jochem16mo ago
I think you've stumbled on a common misconception. A lot of beginners assume querySelector is something that keeps running and keeps updating its results, or that its result is magic and keeps anything that matches up to date with what you do with it, but it's not. The code runs top to bottom, then is done. You're selecting everything with the delete class on it at the start, which is nothing because there's no tasks yet, and then later you're adding the delete eventlistener to all the selected elements (still nothing, still no tasks). When you add a task, there will suddenly be an element with the class delete, but the original querySelector and addEventListener will have run and won't run again automatically just because the DOM changed
const form = document.getElementById('taskForm');
const taskInput = document.querySelector('.task-input');
const dueDateInput = document.querySelector('.due-date');
const taskBar = document.querySelector('.task-bar');
const editButton = document.querySelectorAll('.edit');
const editForm = document.getElementById('taskForm-edit');

form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent default form submission
let taskDescription = taskInput.value;

const task = `
<li class="task">
<div class="details">
<input type="checkbox" name="" id="" />
<p>${taskDescription}</p>
</div>
<div class="buttons">
<button><i class="fa-solid fa-pen-to-square edit"></i></button>
<button class="delete">❌</button>
</div>
</li>`;
task.querySelector('.delete').addEventListener('click', (e) => {
console.log('hi');
});
taskBar.insertAdjacentHTML('beforebegin', task);
});
const form = document.getElementById('taskForm');
const taskInput = document.querySelector('.task-input');
const dueDateInput = document.querySelector('.due-date');
const taskBar = document.querySelector('.task-bar');
const editButton = document.querySelectorAll('.edit');
const editForm = document.getElementById('taskForm-edit');

form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent default form submission
let taskDescription = taskInput.value;

const task = `
<li class="task">
<div class="details">
<input type="checkbox" name="" id="" />
<p>${taskDescription}</p>
</div>
<div class="buttons">
<button><i class="fa-solid fa-pen-to-square edit"></i></button>
<button class="delete">❌</button>
</div>
</li>`;
task.querySelector('.delete').addEventListener('click', (e) => {
console.log('hi');
});
taskBar.insertAdjacentHTML('beforebegin', task);
});
This should solve the problem. You have to add the listener every time you add an element, but you can just add it to the element that was just created hang on, there's an error in my code
hotsauce4dayz
hotsauce4dayz16mo ago
Okay Thanks for helping me in this
Jochem
Jochem16mo ago
I had to change it up a little:
form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent default form submission
let taskDescription = taskInput.value;

const task = document.createElement('li');
task.classList.add('task');
task.innerHTML = `<div class="details">
<input type="checkbox" name="" id="" />
<p>${taskDescription}</p>
</div>
<div class="buttons">
<button><i class="fa-solid fa-pen-to-square edit"></i></button>
<button class="delete">❌</button>
</div>`;
task.querySelector('.delete').addEventListener('click', (e) => {
console.log('hi');
});
taskBar.prepend(task);
});
form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent default form submission
let taskDescription = taskInput.value;

const task = document.createElement('li');
task.classList.add('task');
task.innerHTML = `<div class="details">
<input type="checkbox" name="" id="" />
<p>${taskDescription}</p>
</div>
<div class="buttons">
<button><i class="fa-solid fa-pen-to-square edit"></i></button>
<button class="delete">❌</button>
</div>`;
task.querySelector('.delete').addEventListener('click', (e) => {
console.log('hi');
});
taskBar.prepend(task);
});
Your way works fine but not if you need to add an event listener because you never have access to the DOM of the newly created elements. I'm making a new LI element, adding the task class, then setting the inside of the LI in much the same way you were. Then I can use querySelector on the LI to get a reference to the delete button, which I can use to add the event listener. Finally, I'm adding the newly created element to taskBar at the top using prepend instead of insertAdjacentHTML
hotsauce4dayz
hotsauce4dayz16mo ago
Okay. Let me test this out!
Want results from more Discord servers?
Add your server