Reputation: 1659
I am using firebase DB to dynamically generate some html using the function below.
function Inventorytable(data) {
var container = document.getElementById('iteminfo');
container.innerHTML = '';
data.forEach(function(InventSnap) { // loop over all jobs
var key = InventSnap.key;
var Items = InventSnap.val();
var jobCard = `
<td class="text-left" id="${key}"><a href>${key}</a href></td>
<td class="text-left" >${Items.PartNumber}</td>
`;
container.innerHTML += jobCard;
})
}
I want to add an event listener to the first td class with id="${key}"
. I know with a normal id
I can use document.getElementById("xxxx").addEventListener
but since this is dynamic and the id
is the firebase key. How do I add an event listener using the element id?
Upvotes: 0
Views: 5920
Reputation: 4584
Create a function to call when all append data
is finished !! I tested with add()
,also for more easy to handle ,add one distinct class name to td
!!!
var data = [
{key:0,val:"Zero"},
{key:1,val:"One"}
]
Inventorytable(data);
function Inventorytable(data) {
var container = document.getElementById('iteminfo');
container.innerHTML = '';
data.forEach(function(InventSnap) { // loop over all jobs
var key = InventSnap.key;
var Items = InventSnap.val;
var jobCard = `
<td class="text-left first" id="${key}"><a href="#!">${key}</a href></td>
<td class="text-left" >${Items}</td>
`;
container.innerHTML += jobCard;
});
add();
}
function add() {
var container = document.querySelectorAll(".first");
[].map.call(container, function(elem) {
elem.addEventListener("click",function(){
console.log(this.id);
}, false);
});
}
<table>
<tr id="iteminfo"></tr>
</table>
Upvotes: 1
Reputation: 337560
You could change your logic to create the td
elements and add the event handler to them at that point. This avoids the issue of deleting the existing HTML within the container
, along with all the existing event handlers. Try this:
data.forEach(function(InventSnap) { // loop over all jobs
var key = InventSnap.key;
var Items = InventSnap.val();
var td0 = document.createElement('td');
td0.id = key;
td0.classList.add('text-left');
container.appendChild(td0);
td0.addEventListener('click', function() {
console.log('clicked!');
});
var a = document.createElement('a');
a.href = '#';
a.innerText = key;
td0.appendChild(a);
var td1 = document.createElement('td');
td1.innerText = Items.PartNumber;
td1.classList.add('text-left');
container.appendChild(td1);
});
Or the equivalent of this in jQuery would be:
data.forEach(function(inventSnap) {
var key = inventSnap.key;
var items = inventSnap.val();
var $td = $(`<td class="text-left" id="${key}"><a href="#">${key}</a></td>`).on('click', function() {
console.log('clicked!');
}).appendTo(container);
container.append(`<td class="text-left">${items.PartNumber}</td>`);
});
Upvotes: 2
Reputation: 943214
Normally: Exactly the same way.
You have the ID in a variable. You can get the element. document.getElementById(key)
.
… but there's a problem.
container.innerHTML += jobCard;
You keep taking the DOM (with any element listeners bound to it), converting it to HTML (which doesn't carry the event listeners across), appending to it, then converting the HTML back to DOM (giving you a new set of elements without the event listeners).
Rather than destroying the elements each time, you should create them using standard DOM. You can then call addEventListener
after creating the element.
data.forEach(function(InventSnap) { // loop over all jobs
var key = InventSnap.key;
var Items = InventSnap.val();
var td = document.createElement("td");
td.setAttribute("class", "text-left");
td.setAttribute("id", key);
td.addEventListener("click", your_event_listener_function);
var a = document.createElement("a");
a.setAttribute("href", "");
a.appendChild(document.createTextNode(key));
td.appendChild(a);
container.appendChild(td);
td = document.createElement("td");
td.setAttribute("class", "text-left");
td.appendChild(document.createTextNode(Items.PartNumber));
container.appendChild(td);
})
You could (either with your original approach or in combination with the above) use delegated events instead:
container.addEventListener("click", delegated_event_listener);
function delegated_event_listener(event) {
if (test_what_element_was_clicked_on(this)) {
do_something_with(this.id);
}
}
Upvotes: 1
Reputation: 7575
I would suggest adding a click handler to the #iteminfo
as otherwise you would have stall event listeners around when you reorganize your table.
var container = document.getElementById('iteminfo');
container.addEventListener( 'click', ( e ) => {
const id = e.target.id;
console.log( id );
} );
var data = [
{ key: 1 },
{ key: 2 },
{ key: 3 },
{ key: 'some-other-key' },
]
function Inventorytable(data) {
container.innerHTML = '';
data.forEach(function(InventSnap) { // loop over all jobs
var key = InventSnap.key;
var jobCard = `<button id="${key}">${ key }</button>`;
container.innerHTML += jobCard;
})
}
Inventorytable( data );
<div id="iteminfo"></div>
Upvotes: 1
Reputation: 14432
You can use event delegation for this:
document.addEventListener('click',function(e) {
if(e.target && e.target.id === "yourID") {
//do something
}
});
Upvotes: 0