Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

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

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

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. ¯\_(ツ)_/¯

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.