Event listeners not attaching after an operation on the page

Hello, for some reason when I use the search field or add a cyclist, the element gets added to the page but the show details and delete button doesnt work. They work on reload however. It's an even listener issue but I tried all sorts of things but doesnt seem to be working. This are the buttons:
<button sec:authorize="hasAnyRole('ADMIN','USER')" th:text="#{cyclist.text13}" class="btn btn-primary show-details-btn"
th:data-target="'#cyclistDetailsModal_' + ${cyclist.id}" data-toggle="modal"><i class="bi bi-eye-fill"></i> Show Details
</button>
<button type="button" class="btn btn-danger delete-cyclist-btn" th:attr="data-cyclist-id=${cyclist.id}">
<i class="bi bi-trash-fill"></i> Delete
</button>
<button sec:authorize="hasAnyRole('ADMIN','USER')" th:text="#{cyclist.text13}" class="btn btn-primary show-details-btn"
th:data-target="'#cyclistDetailsModal_' + ${cyclist.id}" data-toggle="modal"><i class="bi bi-eye-fill"></i> Show Details
</button>
<button type="button" class="btn btn-danger delete-cyclist-btn" th:attr="data-cyclist-id=${cyclist.id}">
<i class="bi bi-trash-fill"></i> Delete
</button>
No description
24 Replies
Aman
AmanOPโ€ข5mo ago
Aman
AmanOPโ€ข5mo ago
import { handleDeleteCyclistEvent, showDetailsEvent, attachSearchCyclistListener } from './handlers.js';

export function initializeEventListeners() {
attachEventListeners('.delete-cyclist-btn', 'click', handleDeleteCyclistEvent);
attachEventListeners('.show-details-btn', 'click', showDetailsEvent);
attachSearchCyclistListener();
}

export function attachEventListeners(selector, event, handler) {
document.querySelectorAll(selector).forEach(element => element.addEventListener(event, handler));
}

document.addEventListener("DOMContentLoaded", initializeEventListeners);
import { handleDeleteCyclistEvent, showDetailsEvent, attachSearchCyclistListener } from './handlers.js';

export function initializeEventListeners() {
attachEventListeners('.delete-cyclist-btn', 'click', handleDeleteCyclistEvent);
attachEventListeners('.show-details-btn', 'click', showDetailsEvent);
attachSearchCyclistListener();
}

export function attachEventListeners(selector, event, handler) {
document.querySelectorAll(selector).forEach(element => element.addEventListener(event, handler));
}

document.addEventListener("DOMContentLoaded", initializeEventListeners);
this is all the code concerning this issue
Chooโ™š๐•‚๐•š๐•Ÿ๐•˜
If attachEventListeners() is the only code that adds event listeners, and it only gets called upon loading of the page, that won't include any new items added later. So the problem is that you are not also adding event listeners immediately after new elements are created.
clevermissfox
clevermissfoxโ€ข5mo ago
Might be a good case for a JavaScript class
class Cyclist (){
constructor(id, name, age, nationality, height)
this.id = id
//etc etc
}
class Cyclist (){
constructor(id, name, age, nationality, height)
this.id = id
//etc etc
}
Aman
AmanOPโ€ข5mo ago
This is not needed bc I have this class in my Spring application. Js is used for adding, updating, searching and deleting records without page refresh. So what you are saying is that when i search something, I should also attach the listeners? And not just on a page load?
clevermissfox
clevermissfoxโ€ข5mo ago
Why not have the event listeners in the class if they all have the same buttons ?
Aman
AmanOPโ€ข5mo ago
Im not sure if its even possible to have listeners in Java spring application
clevermissfox
clevermissfoxโ€ข5mo ago
Ok Idk what a spring application is then just add event listeners scoped to the buttons you need
Chooโ™š๐•‚๐•š๐•Ÿ๐•˜
What I am saying is the event listeners must be attached to all new elements in the DOM that you expect to respond to user interaction. This must be done regardless of the reason that the new elements are being added. It doesn't matter if it's because of search or some other reason.
Aman
AmanOPโ€ข5mo ago
is a framework for the Java platform
Chooโ™š๐•‚๐•š๐•Ÿ๐•˜
You could also use event delegation. That would involve placing an event listener only on the container and checking the event target to determine which element the event happened on.
Aman
AmanOPโ€ข5mo ago
I will try it now. Can I get back to you if it doesnt work?
clevermissfox
clevermissfoxโ€ข5mo ago
It will work, event delegation is what you need. Thatโ€™s the proper word for what I said about an event listener scoped to the buttons. Add it on the container, like say the ul that holds each li row . Then:
if(!e.target.closest(โ€˜buttonโ€™) return
if (e.target.closest(โ€˜.show-details-btnโ€™) {//show details handler }
if (e.target.closest(โ€˜.delete-cyclist-btnโ€™) {//delete handler}
if(!e.target.closest(โ€˜buttonโ€™) return
if (e.target.closest(โ€˜.show-details-btnโ€™) {//show details handler }
if (e.target.closest(โ€˜.delete-cyclist-btnโ€™) {//delete handler}
Etc Also from a quick google you can add event listeners on a class in Java Spring application but looks like a lot of code to create and publish @EventListener
Aman
AmanOPโ€ข5mo ago
I reattached the listener when for example I search and table is loaded with new data but I just get this error message
data-target attribute is missing on the button element.
data-target attribute is missing on the button element.
export function showDetailsEvent(event) {
event.preventDefault();
const target = event.target.closest('.show-details-btn');
if (target) {
const dataTarget = target.getAttribute('data-target');
console.log('data-target:', dataTarget);
if (dataTarget) {
const cyclistId = dataTarget.split('_').pop();
showDetails(cyclistId);
} else {
console.error('data-target attribute is missing on the button element.');
}
}
}
function showDetails(cyclistId) {
const detailsModal = document.getElementById('cyclistDetailsModal_' + cyclistId);
if (detailsModal) {
$(detailsModal).modal('show');
} else {
console.error(`Modal with ID cyclistDetailsModal_${cyclistId} not found.`);
}
}
export function showDetailsEvent(event) {
event.preventDefault();
const target = event.target.closest('.show-details-btn');
if (target) {
const dataTarget = target.getAttribute('data-target');
console.log('data-target:', dataTarget);
if (dataTarget) {
const cyclistId = dataTarget.split('_').pop();
showDetails(cyclistId);
} else {
console.error('data-target attribute is missing on the button element.');
}
}
}
function showDetails(cyclistId) {
const detailsModal = document.getElementById('cyclistDetailsModal_' + cyclistId);
if (detailsModal) {
$(detailsModal).modal('show');
} else {
console.error(`Modal with ID cyclistDetailsModal_${cyclistId} not found.`);
}
}
This is what I did
No description
Aman
AmanOPโ€ข5mo ago
What's weird is that delete event listener works but not for show details
export function initializeEventListeners() {
attachEventListeners('.delete-cyclist-btn', 'click', handleDeleteCyclistEvent);
attachEventListeners('.show-details-btn', 'click', showDetailsEvent);
attachSearchCyclistListener();
reattachEventListeners();
}
export function initializeEventListeners() {
attachEventListeners('.delete-cyclist-btn', 'click', handleDeleteCyclistEvent);
attachEventListeners('.show-details-btn', 'click', showDetailsEvent);
attachSearchCyclistListener();
reattachEventListeners();
}
แผ”ฯฯ‰ฯ‚
i have an idea for you throw away all your javascript, use a form, change the button type to submit, set a formaction to whatever you want to do (delete, edit, cookies, shoes, pink fluffy unicorns dancing on rainbows...) and set the value of the buttons to the cyclist.id
Aman
AmanOPโ€ข5mo ago
That didnt make sense at all sorry๐Ÿฅน . Im not made for js or frontend but my current college project requires me to do it.
แผ”ฯฯ‰ฯ‚
im building an example for you
Aman
AmanOPโ€ข5mo ago
thanks a lot๐Ÿ‘Š
แผ”ฯฯ‰ฯ‚
https://jsfiddle.net/9eLths7b/ <-- took a while, but enjoy the idea is simple: the <form> is the main container, and all buttons submit to the form but then, im stopping the submit event (with e.preventDefault();) and use the value in button.getAttribute('formaction') to check what the action is then, there's an object that maps action names to functions (it's called actions) if an action name is a key in the variable actions, then it calls the function associated (i did this a bit shoddily, since you should use an object without any prototype for this, or a map or use actions.hasOwnProperty) the function is receiving the button and event (you can decide what to do) for the function addTableRow i'm reading the contents of the <template> tag and shoddily filling in the text for each table cell (<td>) then, i just add the stuff to the table, which is pretty shoddy but works for the purpose of demonstrating for the function deleteTableRow, i find the parent tr and remove it from the document this isn't the intented use of the formaction attribute, but it works fine
clevermissfox
clevermissfoxโ€ข5mo ago
I canโ€™t swim through this fractured code and screen shows. The console error is what you defined in your โ€œelseโ€ so it sound like itโ€™s caught somewhere . Start putting breakpoints in your code line by line or console logs. Ensure target is returned, then try dataTarget then cyclistID. Make sure your selectors and attr names are exact. It sounds like the if(target) isnโ€™t even passing
Aman
AmanOPโ€ข5mo ago
Thanks for spending your valuable time to explain this so clearly to me. Really I appreciate it. I really hope I manage to fix this now Yeah I will add these checks in places. Hopefully, I manage to fix it now Thanks all!!
แผ”ฯฯ‰ฯ‚
this isn't a fix this is a "throw it all out and start over" by the way, if you decide to do not use my method, at least i very strongly recommend that you use a <template> appending to innerHTML will cause huge performance issues, because the browser has to parse the ever-increasing html over and over and over again and you're then re-adding the events you threw away by editing the html on top of that, you're adding an event per button, and you may have lots of buttons, which can cause performance issues
Chooโ™š๐•‚๐•š๐•Ÿ๐•˜
const dataTarget = target.getAttribute('data-target');
const dataTarget = target.getAttribute('data-target');
I don't know if you have elements that you haven't shown us, but I don't see any element that has this attribute. Also, you did not indicate if you started using event delegation or not. If you use it, you have to verify that the right type of element was clicked before you do this kind of processing. When you add an event listener to a parent container, unintended targets can trigger the event handler. For example, if you use event delegation on a calculator app, the spaces between the buttons are clickable, and they don't have the same properties that buttons would, so assuming that every click is on a button would cause problems.
Want results from more Discord servers?
Add your server