Problem: How do I make a function work on rows created after initial page load?
On page load my code fetches data from a Mongo DB and creates table rows for each entry with a for (item of data) loop. When this is done, some code is run that makes all the just created rows clickable and expandable. It works well. This is the code:
$('tbody tr').not('.hidden-row').on('click', function(event){
$('tbody tr.opentr').not(this).removeClass('opentr')
$(event.currentTarget).toggleClass('opentr')
var hiddenRow = $(this).next(".hidden-row")
var rowExists = $(hiddenRow).length
if (rowExists) {
$('tbody .hidden-row').not(hiddenRow).hide()
$(hiddenRow).toggle()
} else {
var expRowContent = $(this).find('.hide').html()
var newExpRow = '<tr class="hidden-row" style="display:none;"><td colspan="7">' + expRowContent + '</td></tr>'
$(newExpRow).insertAfter(this)
$('tbody .hidden-row').not(hiddenRow).hide()
$(this).next('.hidden-row').toggle()
}
})
All good. Now the user triggers the adding of a new row which is inserted at the end of the table. Works fine.
But this row is not clickable, because the code above binds to the elements that were created when it was run.
If I simply run the code again, my dynamically added row is now clickable and expandable. Great — except for the fact that for some reason this makes all the already created rows not clickable. Only the just created row is now clickable.
I have been digging into the console but can't see any code changes to the existing rows that would explain this. Why it that? And should this be approached in a different way?
The comments have advised Event delegation. Here's an example:
// add the event listener to the entire table body
$('table tbody').on('click', (evt)=>
/* Check if the target is a <tr> or a descendant of <tr>
if(evt.target.matches('tr') || evt.target.matches('tr *')) {
// ... your old event listener code goes here
}
});