addEventListener executing after rest of JS

I recently encountered something that I’m struggling to explain.
For context, I’m learning DOM manipulation with JS and doing the super nice projects mentioned in this video - Build 15 JavaScript Projects - Vanilla JavaScript Course - YouTube.

I recently add an issue when trying to select some buttons that were added dynamically.
I have setup a function that is dynamically adding buttons to the DOM. I initially add it to the page with window.addEventListener. Then I try to select these buttons with a query selector, but it doesn’t work.

Now if I remove the window.addEventListener and just execute directly the callback function, then I can select the button that I just created dynamically.

I’d say that because the callback is wrapped inside of the event listener, it’s actually executed after the rest of JS, but I’m confused as I thought event listener were regular JS, so should be executing at same time.

My codepen is here is you want to take a look - https://codepen.io/Gjloss/pen/eYgPqRO?editors=1011.

Big thanks to anyone taking the time to check it out and have a great day!

What you have done is this:

function render() { /* do stuff */ }
window.addEventListener('DOMContentLoaded', render);

It sets up to run render when DOM is ready and not before. And this is absolutely the correct way to do things in your case. You just need to make sure your query executes also after DOM is ready, not before.

Next snippet would run synchronously and your buttons would be available during the same loop:

window.addEventListener('DOMContentLoaded', render());

In this case render runs immediately and by default returns undefined (because you have not specified any return value). On DOM load, though, nothing will get executed. So as far as the event goes, it would be equivalent of this:

window.addEventListener('DOMContentLoaded', undefined);

Thx a lot for taking a look, much appreciate you taking the time to look at my code and help me grow!

When checking the answer though, I think I understand the second part but I don’t see how it applies to what I’ve done

window.addEventListener("DOMContentLoaded", function() {
      //do stuff to add  buttons  with innerHTML applied to an existing DOM element 
});

//Try and select the buttons that were created once DOM Content is loaded
const buttons = buttonArea.querySelectorAll(".btns");
console.log(buttons); //return empty object while buttons are displayed

However

 //do stuff to add  buttons  with innerHTML applied to an existing DOM element 

const buttons = buttonArea.querySelectorAll(".btns");
console.log(buttons); //return an array-like with all buttons while buttons are displayed 

With both approach, I can display buttons, but with the first one, I can’t get them. I don’t get why

Try logging this out.

window.addEventListener("DOMContentLoaded", function() {
  console.log('DOMContentLoaded: When do I run?')
});

console.log('Outer scope: When do I run?')

If the Outer scope console.log was trying to query for buttons created inside DOMContentLoaded what would happen?

1 Like

Thx @lasjorg , indeed console displays first the Outer Scope one. Then am I to understand that addEventListener is running async?

No, the event listener is added pretty much instantly. But it takes a while for the DOM to load.

Basically the order in which stuff is happening is this:

  • event listener is added to window
  • console.log('Outer scope...')
  • DOM is loaded and event listener fires
  • console.log('DOMContentLoaded....')

It’s usually a good idea to put the whole script inside the listener callback like this:

window.addEventListener("DOMContentLoaded", function() {

    // your entire code goes here

});
1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.