NUS Hackers Wiki
NUS Hackers Wiki
  • NUS Hackers Wiki
  • Hackerschool
    • Virtual Machines and Linux
    • Beginners' Guide to the Terminal
      • Introduction to the Terminal
      • Modern Shell Tools
      • Shell Scripting
      • Real World Scripting
      • Resources
    • Self-Hosting: Three Easy Pieces
      • 1. Setting up your server
      • 2. Running Services
      • 3. Monitoring your server
    • Vim
    • Introduction to Zig
      • Language Basics
      • Error Handling
      • Memory Management
      • Working with C
      • Exploring comptime
    • CI/CD with Github Actions
      • Background
      • Basics of Github Actions
        • Target workflow
        • Running unit tests
        • Linting code
        • Deploying to Github Pages
      • Advanced use cases
        • Pollers
        • Github script
        • Executing third-party scripts
        • Reusable workflows
      • Cookbook
    • Lightning Git
      • Git Concepts
      • Getting Started with Git
      • Making your first commit
      • Branching
      • Merge Conflicts
      • Integrating remote repositories
      • Collaborative Workflows
      • Commit Manipulation and Reflog
      • Interactive rebasing
      • filter-repo
  • Orbital
    • JavaScript
      • Browser Developer Tools
      • Getting Started
      • Datatypes
      • Operators and Operations
      • Loops and Conditions
      • Functions
      • Strings
      • Arrays
      • HTML
        • Getting Started
        • Tag Attributes
        • HTML Forms
        • Browser Inspector
      • CSS
        • Selectors
        • Colors in CSS
        • Measurements in CSS
        • The Box Model
        • Adding Styles - Part 1
        • Adding Styles - Part 2
      • Working with the DOM
        • Querying the DOM - Selectors
        • Querying the DOM - Element Attributes
        • Querying the DOM - Element Styles
        • Events with JS and HTML
        • Exercise: Click Counter
        • Editing the DOM
        • Fetch Requests
        • Exercise: The NUSMods API
    • React
      • Setup
      • State
    • React Native
      • Setup
      • Intro to JSX
      • Basic Syntax
      • Handling UI
      • Props
      • State Management
    • Git
      • Setup
      • Command Glossary
      • Fundamental Concepts
        • Getting Started
        • Integrating Remote Repositories
        • Branching
        • Merge Conflicts
      • Collaborative Workflows
        • Fork and PR Workflow
        • Branch and PR Workflow
      • Advanced Concepts
        • Ignoring Files
        • Commit Message Conventions
        • Github Collaborators
        • CI/CD with Github Actions
        • Advanced Git Commands
      • FAQ
    • Telegram Bot
      • Creating a TeleBot
      • API Calls
      • Telebot Basics
      • Integrating API's
    • Relational Database
      • Database Overview
      • Database Design
      • Entity Relationship Diagram
      • SQL Basics & PostgreSQL
    • TypeScript
      • Types and Interfaces
      • Utility Types
      • Typing Component Props, Events, and Hooks
      • Why You Should Avoid Using any (and What to Do Instead)
      • TypeScript Tricks You’ll Use All the Time in React
Powered by GitBook
On this page
  • Adding JS to HTML pages
  • Event Listeners
  • Adding a click event listener to the button
  • The problem
  • Next steps
Edit on GitHub
Export as PDF
  1. Orbital
  2. JavaScript
  3. Working with the DOM

Events with JS and HTML

Adding JS to HTML pages

There are two ways to add JS code into HTML pages. The first way is to make use of the <script> tag:

<script>
    // code goes here
</script>

The second way is to write the code in a separate file, save it as with the .js file extension, and import it using the <script> tag:

<script src="script.js"></script>

This is the recommended method which we will stick to for this guide, but note that for shorter programs (3-4 lines long) it is sometimes easier to use the first method.

Event Listeners

Event Listeners in JavaScript are functions that wait and "listen" for events (like clicks) on the page. Once the event happens, they can execute a listener function. These are nullary functions that have no return value.

An event listener can be added either to an element on the page (like a button, a paragraph or a form), or the page itself. The method to add an event listener is addEventListener as is used as follows:

document.addEventListener(event, listener); // add a listener to the page itself
element.addEventListner(event, listener); // add a listener to a particular element

Adding a click event listener to the button

Go back to the html file from before, and remove the button's onclick attribute. Then, open a new file and save it as script.js. Here, write the following code:

let button = document.getElementById("hello");
button.addEventListener("click", () => alert("Hello!"));

The first line will query for the button, and the second line adds an event listener. The event it listens for is "click", and the listener is a lambda expression for an anonymous nullary function.

Save the code, and import it into the html document by adding the following line into the head of the document:

<script src="script.js"></script>

Now save the file, reload the page, click the button and...

Hmmm. Nothing is happening. Go back, check the syntax and spelling. No issues there. Check the browser console, and aha. There's an error: Uncaught TypeError: button is null

Well, we're running the same query that we were running in the Browser console in the previous sections, and that worked fine. What's the issue here?

The problem

Let's take a look our html file:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="../styles.css">
        <script src="script.js"></script>
        <title>My web page</title>
    </head>
    <body>
        <h1>Hello world</h1>
        <button id="hello">Say hello</button>
    </body>
</html>

The browser reads the file from top to bottom, rendering elements and styles as it reads them line by line. This creates the issue that the JavaScript code is read and executed before the rest of the document is rendered. So the button we're querying for does not exist by the time the code is read, which means that querying the document for the button returns null, hence the TypeError we see.

Fix 1

The easiest way to fix it is to execute the code after the document is rendered. This involves moving it to the bottom of the file:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="../styles.css">
        <title>My web page</title>
    </head>
    <body>
        <h1>Hello world</h1>
        <button id="hello">Say hello</button>
        <script src="script.js"></script>
    </body>
</html>

Save the file, reload the page, and try clicking the button. It should display a popup with "Hello!" on it. If it doesn't, check for syntax errors or spelling mistakes in the code and in your HTML file, and make sure the file is saved and the page is reloaded.

This is an easy way to fix the issue, and is quite convenient. However, it means that the code is not executed until the entire page is loaded and rendered, including images, stylesheets and other large files. So if there is just one single file or image that is taking time to load, the JS code will not be executed until it is loaded, which could cause some inconvenience as event listeners won't be added in time.

Fix 2 (recommended)

The second option is to wait till the elements of the page are loaded into the DOM (which is done before rendering the elements on the page itself). This will happen much earlier and is faster than waiting for the elements to render. To do this, there is a special event only applicable to the document itself. This event is called "DOMContentLoaded" (case-sensitive). It can be used as below:

document.addEventListener("DOMContentLoaded", function() {
    // add event listeners to elements on the page
});

This will allow the JS code to be executed much before the page renders, so event listeners and other JS-dependent elements or features are ready as soon as the page is rendered and displayed to the user. Let's apply this to our code:

// In the script.js file:
document.addEventListener("DOMContentLoaded", function() {
    let button = document.getElementById("hello");
    button.addEventListener("click", () => alert("Hello!"));
});
/*
Note that function() {...} is an alternate way of
 creating anonymous functions spanning multiple lines,
 as explained much earlier in the guide
*/

Now move the <script> tag back into the head of the document, save the file, reload the page on the browser, and the button should work:

You can remove a listener from an element using the removeEventListener function:

element.removeEventListener(event, listener); // to remove a specific listener
element.removeEventListener(event); // to remove all listeners for an event

Next steps

Next, we'll make a simple example of querying and updating the DOM using a click counter.

PreviousQuerying the DOM - Element StylesNextExercise: Click Counter

Last updated 12 months ago

Its hard to tell, but I am clicking the button I promise