Sunday 12 March 2023

Spot The Bug: Misfiring with DOM manipulation

Hello, readers.

For our next episode of Spot The Bug, we're going to deal with a very basic rookie error programmers tend to make when they're into their first few forays into JavaScript and DOM manipulation.

No bugs are safe!


Many years ago, I had this bright idea to change the look and feel of the website depending on the browser's time of day. Just a bit of JavaScript and CSS, amirite?!

Without further ado, I'm gonna show you the code. I've generated some content using ChatGPT.
<!DOCTYPE html>
<html>
    <head>
        <title>Day and Night</title>

        <style>
            body
            {
                font-family: impact;
                font-size: 18px;
                padding: 10px;
                border-radius: 10px;
                text-align: center;
            }

            .day
            {
                background-color: rgb(100, 100, 255);
                color: rgb(0, 0, 0);
            }

            .night
            {
                background-color: rgb(0, 0, 50);
                color: rgb(255, 255, 255);
            }
        </style>

        <script>
            var body = document.getElementsByTagName("body");
            var d = new Date();

            if (body.length == 1)
            {
                body[0].className = "day";

                if (d.getHours() > 18 || d.getHours() < 6)
                {
                    body[0].className = "night";
                }                
            }
        </script>    
    </head>

    <body class="day">
        <p>
            Day and Night, two sides of the same coin<br />
            One brings light, the other, sweet peace to enjoy.<br />
            Day breaks the darkness with a brilliant light<br />
            A new chance to live, to love, to take flight.
        </p>

        <p>
            People hurry, bustle, and rush to their goals<br />
            While the sun shines, hearts beat with new roles.<br />
            But as day wanes, and the light begins to fade<br />
            Night creeps in, with a cool and soothing shade.<br />
        </p>

        <p>
            Nightfall brings a stillness, a calming repose<br />
            Stars twinkle, the moon glows, and the world slows.<br />
            Dreams take flight, worries rest, and all is right<br />
            In the embrace of the night, till the morning light.
        </p>

        <p>
            So here's to day and night, both bright and fair<br />
            May they bring joy, peace, and love everywhere.
        </p>
    </body>
</html>


What went wrong

Nothing happened I tested with this change. It was 3 PM in the afternoon at the time, so this should have worked to change the default background color.
if (d.getHours() > 12 || d.getHours() < 6)
{
  body[0].className = "night";
}    


Yep, it remained a lovely shade of sky-blue regardless of what I did.




Why it went wrong

One thing about DOM manipulation using JavaScript - the DOM elements have to exist when the script is referencing them. And if the script is running before the HTML body has been generated, then it's a no-go.

The way I had structured it, the script tag was placed before the body tag. And the script was referencing the body tag which didn't exist at the time it was running! So it wasn't that my code was not running correctly or even not running; but rather, it had nothing to act on.

How I fixed it

The easy and lazy solution would be to just place the script tag after the body tag. It would absolutely work. But generally, I prefer to keep the script tag in the head tag.

So the neater solution, at least in my view, would be to first encapsulate the code in a function.
function generateScene()
{

  var body = document.getElementsByTagName("body");
  var d = new Date();

  if (body.length == 1)
  {
    body[0].className = "day";

    if (d.getHours() > 18 || d.getHours() < 6)
    {
      body[0].className = "night";
    }                
  }                
}


And then add an onload attribute in the body tag to specify that the function would run once the body tag loaded.
<body class="day" onload="generateScene()">


See the difference? Like day and night! (hur hur)




Moral of the story

This was a lesson I learned early into my career of using JavaScript. And I suspect it's much the same with all fledgling developers doing front-end stuff. It really served to drive home the point that when you execute the code is pretty damn important.

Good day! (or night!)
T___T

No comments:

Post a Comment