0

I am building SPA with only use vanilla javascript now.
At first, router check location.pathname and render HTML view that matchs the path.
This is code : document.querySelector("#app").innerHTML = await view.getHtml();

After that code, I wrote call javascript function from another module that matches current location pathname. It's for add event listener on html elements.

The problem is, it shows error : Cannot read property 'classList' of null, I think this is because of loading order. Because javascript didn't wait for all html rendered, it try to add eventlistener to null.

So I want to make javascript function called after html elements all loaded like <script defer> in html. (I can't use it, I should do it only by javascript code)

Does anybody know how to that? My current code is here...

const router = async () => {
  // check current pathname and match the view
  ...
  document.querySelector("#app").innerHTML = await view.getHtml();
  const path = location.pathname;
  if (path === "/") main();
  if (path === "/list") list();
}

document.addEventListener("DOMContentLoaded", () => {
  router();
});
hello
  • 131
  • 1
  • 10
  • 1
    Did you try ```window.addEventListener('load', ()=> {router();})``` ? – Palash Jul 28 '21 at 04:28
  • @Maxzeroedge yes, but it still have error : `Cannot read property 'addEventListener' of null` – hello Jul 28 '21 at 04:34
  • in which part? `window.addEventListener` or `document.addEventListener`? You need to check why you aren't getting window or document instance is not available – Palash Jul 28 '21 at 04:36
  • @hello If you want it all loaded like `defer`, why don't set your script inside a `.js` file and include it within your webpage? Just want to remind you that "the `defer` and `async` attributes must not be specified if the src attribute is not present". Or simplier, use JS render blocking? – Huy Phạm Jul 28 '21 at 04:37
  • @Maxzeroedge in HTMLelement.addEventListener. @HuyPhạm because at first it rendered with only one div (`
    `), and then router draws html elements in #app, so i want to call javascript after all of this
    – hello Jul 28 '21 at 04:42
  • Please see [How to make JavaScript execute after page load?](https://stackoverflow.com/questions/807878/how-to-make-javascript-execute-after-page-load) and [Vanilla JavaScript equivalent of jQuery's $.ready() - how to call a function when the page/DOM is ready for it](https://stackoverflow.com/questions/9899372/vanilla-javascript-equivalent-of-jquerys-ready-how-to-call-a-function-whe/9899701#9899701) – ggorlen Aug 29 '22 at 22:22

1 Answers1

2

You have 2 options, as Maxzeroedge commented, you can add a listener to the load event in the DOM so that block gets executed after all the elements are loaded, so you can reference all the object from your app.

The second option is simpler and is to start your app in the last line of the body, like:

<html>
  <head>
    ...
  </head>
  <body>
    // All your elements here.
    <script type="text/javascript" src="./-your-script-.js"></script> // The last line is your script call.
  </body>
</html>

This will run after all elements are declared so you don't have any reference problems.

Sebastián Espinosa
  • 2,123
  • 13
  • 23