JavaScript JavaScript and the DOM Getting a Handle on the DOM Select a Page Element By Its ID

Carlos Chavez
Carlos Chavez
5,502 Points

How does the order in which you place your HTML elements matter?

When I tried selecting the button element by ID, I had it under the script tags and it didn't run. I thought that the js file could manipulate all the HTML elements, and that the script tags was recommended to be in the end only for 'best practice' purposes. Does anyone know about a specific order it should follow?

<html>
  <head>
    <title>JavaScript and the DOM</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <h1 id="myHeading">JavaScript and the DOM</h1>
    <p>Making a web page interactive</p>

    <script src = "app.js"></script>
    <button id = "myButton">Change heading color</button>
  </body>
</html>
const myHeading = document.getElementById('myHeading');
const myButton = document.getElementById('myButton');

myButton.addEventListener('click', () => { myHeading.style.color = 'red'; });

1 Answer

Joseph Wasden
Joseph Wasden
20,403 Points

tl;dr: The browser stopped parsing the HTML when it found your script tag, so the button didn't "exist" yet for the javascript to use. You need to tell your script tag how to handle this situation so it still does what you expect, and there are a couple ways. (see below)

This has to do with how browsers work; how they parse information and then render it to the page. Here's an excerpt from a relevant resource on MDN, under section Parsing, last paragraph of Building the DOM Tree:

...When the parser finds non-blocking resources, such as an image, the browser will request those resources and continue parsing. Parsing can continue when a CSS file is encountered, but <script> tags—particularly those without an async or defer attribute—block rendering, and pause the parsing of HTML. Though the browser's preload scanner hastens this process, excessive scripts can still be a significant bottleneck.

https://developer.mozilla.org/en-US/docs/Web/Performance/How_browsers_work

In your example, you can sidestep the script tag pausing the HTML parsing by adding the async attribute to the script tag. This means that the script file will load asyncronously, or in a non blocking manner, allowing the html to parse and finish building the DOM, which is completed in time for the javascript to find the css selector it needs to work.

But this feels a little bit hacky. Without more testing, I'd be concerned that this only works because our webpage example is so simple. It may be more advantageous to clearly wait for all dependent page resources to be loaded before executing your javascript. You can do that by using window.onload. That way, you can leave the script tag in the current position in HTML, and it will only execute when all the page resources are loaded. See example below.

https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event

window.onload = () => {
  const myHeading = document.getElementById('myHeading');
  const myButton = document.getElementById('myButton');

  myButton.addEventListener('click', () => { myHeading.style.color = 'red'; });
}

Of course, this involves some tradeoffs. I recommend giving the above links a read. Fascinating stuff.

Or, you could just move the script tag to the end of your html body tag. ¯\_(ツ)_/¯

Carlos Chavez
Carlos Chavez
5,502 Points

Thank you Joseph! I see now. No matter how simplified this course tries to make learning JS, there's always some fascinating process going on under the hood. But I trust that we will be learning everything at the right pace.