You might look into javaScript event delegation. There are many answers on SO (an example here) and many good articles ( here or here ).
Basically the idea you had is actually a good solution. So, instead of binding - let's say - one hundred rows with their own event handlers, you bind only their common parent which will fire an event when any of its child will receive a mouse input.
Roughly speaking instead of this:
$('tr').on("click", function() {});
You will do this:
$('table').on('click', 'tr', function() {});
This is obviously a very simplified example, but it should be enough to build a good pattern upon.
As a side note, it's a very interesting thing (well, at least for me...) to inspect the event that is fired doing something like:
$('table').on('click', 'tr', function(evt) {
console.log(evt);
});
And see how much information an event carries, and how much useful information you get out of the box with a simple click or mouse enter.
VanillaJs
Of course the same result can be achieved without any library.
A simple implementation using Vanilla JS can be taken from David Walsh's article linked at the beginning of the answer, it goes roughly like this:
// Get the element, add a click listener...
document.getElementById("#myTable").addEventListener("click", function(e) {
// e.target is the clicked element.
// Check if it was a <tr>...
if(e.target && e.target.nodeName == "TR") {
// Element has been found, do something with it
}
});
If you try this code though chances are that the actual target.element is the <td>, and not the <tr> we want.
This means we have to be a bit more clever and walk the DOM upwards to see if the clicked element (<td>) is contained in the one we really want (<tr>).
A rough implementation to get you started would look like this:
function walk(startEl, stopEl, targetNodeName) {
if (!startEl || startEl === stopEl || startEl.nodeName === 'BODY') {
return false;
}
if (startEl.nodeName === targetNodeName) {
// Found it, return the element
return startEl;
}
// Keep on looking...
return walk(startEl.parentNode, stopEl, targetNodeName);
}
const container = document.getElementById('myTable');
container.addEventListener('click', (e) => {
const clickedElm = walk(e.target, container, 'TR');
console.log(clickedElm);
if (clickedElm) {
clickedElm.classList.add('clicked');
}
})
See this fiddle or the snippet below:
function walk(startEl, stopEl, targetNodeName) {
if (!startEl || startEl === stopEl || startEl.nodeName === 'BODY') {
return false;
}
if (startEl.nodeName === targetNodeName) {
return startEl;
}
return walk(startEl.parentNode, stopEl, targetNodeName);
}
const elem = document.getElementById('myTable');
elem.addEventListener('click', (e) => {
const clickedElm = walk(e.target, elem, 'TR');
console.log(clickedElm);
if (clickedElm) {
clickedElm.classList.add('clicked');
}
})
table {
width: 100%;
}
tr {
background: #ddd;
}
.clicked {
background: teal;
}
<table id="myTable">
<tr>
<td>one</td>
</tr>
<tr>
<td>two</td>
</tr>
<tr>
<td>three</td>
</tr>
<tr>
<td>four</td>
</tr>
<tr>
<td>five</td>
</tr>
<tr>
<td>six</td>
</tr>
</table>
.on()Method should not cost you in performance, cause there's no event until your element is the initiator of such event. What is sluggish? the toggling?jsperfto check which selectors are better to use.:last, [id^="someid"]etc. which i guess might be there.