I want to get each element reference and want to add event listener on each item, but when I add HTML using innerHTML, I am not able to use it outside anywhere. How can I use it everywhere and instead of just event listener, how can I reference it also? I know there are other ways to add HTML using javascript, but for now, I want to do it with innerHTML.
const mybtn = document.getElementById('maybe');
const parent = document.getElementById('parent');
mybtn.addEventListener('click',function(e){
parent.innerHTML = `<div>
<h1 id="one" >Hello 1</h1>
<h1 >Hello 2</h1>
<h1 >Hello 3</h1>
<h1 >Hello 4</h1>
</div>`
});
const one = document.getElementById('one');
one.addEventListener('click',function(e){
alert('one');
});
<div id="parent"></div>
<button id="maybe">Set</button>
CodePudding user response:
You are attempting to add the eventListener to elements which are yet to be created. As currently your elements are only added to parent on buttonClick of myBtn
.
If you add the event listener when the elements are created then your code will work.
const mybtn = document.getElementById("maybe");
const parent = document.getElementById("parent");
mybtn.addEventListener("click", function (e) {
parent.innerHTML = `<div>
<h1 >Hello 1</h1>
<h1 >Hello 2</h1>
<h1 >Hello 3</h1>
<h1 >Hello 4</h1>
</div>`;
const one = document.querySelector(".one");
one.addEventListener("click", function (e) {
alert("one");
});
});
<div id="parent"></div>
<button id="maybe">Set</button>
CodePudding user response:
The keyword that you would want to google for is event delegation
.
To understand the issue you are facing, you will need to understand the executing order of your code.
mybtn.addEventListener('click',function(e){
parent.innerHTML = `<div>
<h1 >Hello 1</h1>
<h1 >Hello 2</h1>
<h1 >Hello 3</h1>
<h1 >Hello 4</h1>
</div>`
});
const one = document.querySelector('.one');
one.addEventListener('click',function(e){
alert('one');
});
In your code, you are adding a click
event on mybtn
that will set the innerHTML
of another HTML element. In addition to that, you also select other elements by className .one
and then add click
event to it. The question is, which one happens first? Your innerHTML
set or querySelector
?
And the answer is the querySelector
.
If you look into the dev tools and put up some checkpoint, you will see that innerHTML
line only run when you actually clicking the button, and might be way after the querySelector
. So by the time the querySelector
runs, your HTML page doesn't even know about any elements that have the class .one
.
So, how would you deal with these dynamically generated elements?
Set the handler after you create the element (IMO, bad way)
You would simply move your click handler to after the innerHTML
set.
mybtn.addEventListener('click',function(e){
parent.innerHTML = `<div>
<h1 >Hello 1</h1>
<h1 >Hello 2</h1>
<h1 >Hello 3</h1>
<h1 >Hello 4</h1>
</div>`
const one = document.querySelector('.one');
one.addEventListener('click',function(e){
alert('one');
});
});
This will ensure that your querySelector
can target the elements you are looking for
Set up event delegation (IMO, better way)
So the problem with the above one is that, you will have to rerun the click
handler whenever you click
the button. With a small app, this is acceptable. However, this is still not a good practice.
Since JS event will bubble up to the parent element, you don't need to target the exact element to add the events. Instead, you can target the parent.
Your code will look something like this
mybtn.addEventListener('click',function(e){
parent.innerHTML = `<div>
<h1 >Hello 1</h1>
<h1 >Hello 2</h1>
<h1 >Hello 3</h1>
<h1 >Hello 4</h1>
</div>`
});
parent.addEventListener('click', function(e) {
if (e.target.classList.contains('one')) {
alert('one');
}
}
What the code is doing is:
- add the
click
event to the parent element - as we know, the event will be bubbling up from the actual.one
element toparent
element, this will be fired when.one
isclick
- we use
e
(theclick
event) to retrievee.target
, which is the element that actual trigger the event - we then check whether that is the element that we are looking for.
You can read more about it here