Marcy Lab School Docs
  • Welcome
  • Student Guidelines & Policies
    • Student Handbook
    • AI Policy
    • Academic Calendar
  • Environment Setup
    • Local Environment Setup - Mac
    • Local Environment Setup - Windows
    • GitHub Setup
    • Postgres Setup
  • How-Tos
    • How To Code at Marcy: Code Style Guide
    • How to Do Short Response and Coding Assignments
    • How to Debug
    • How to PEDAC
    • How to Create A GitHub Organization and Scrumboard
    • How to Create Projects with Vite
    • How to Deploy on GitHub Pages
    • How to Deploy on Render
    • How to Test your API with Postman
  • Mod 0 - Command Line Interfaces, Git, and GitHub
    • Overview
    • 1. Command Line Interfaces
    • 2. Git & GitHub
    • 3. Git Pulling & Merging
    • 4. Git Branching & PRs
  • Mod 1 - JavaScript Fundamentals
    • Overview
    • 1. Intro to Programming
    • 2. Errors
    • 3. Node & Node Modules
    • 4. Variables, Functions & String Methods
    • 5. Control Flow, typeof, and Math
    • 6. Loops
    • 7. Arrays
    • 8. Objects
    • 9. Higher Order Functions: Callbacks
    • 10. Higher Order Functions: Array Methods
    • 11. Regex
  • Mod 2 - HTML, CSS & the DOM
    • Overview
    • 1. HTML
    • 2. CSS
    • 3. Accessibility (a11y)
    • 4. The Document Object Model (DOM) API
    • 5. Events
    • 6. Forms
    • 7. The Box Model and Positioning
    • 8. Flexbox
    • 9. Grid & Media Queries
    • 10. ESModules
    • 11. Vite
    • 12. LocalStorage
  • Mod 3 - Async & APIs
    • Overview
    • 1. Promises
    • 2. Fetch
    • 3. Building a Fetching App
    • 4. Async & Await
    • 5. A Generic Fetch Handler
  • Mod 4 - Project Week!
    • Important How Tos and Guides
      • How to Create a GitHub Organization and Scrum Board
      • How To Start a Project with Vite
      • How To Deploy a Project with GitHub Pages
    • Project Week Overview
    • Agile Methodologies
    • Deliverables & Milestones
    • Technical Requirements Checklist
    • Free API List
    • Collaborative GitHub
  • Mod 5 - Object-Oriented Programming
    • Overview
    • 1. Intro to OOP, Encapsulation, Factory Functions, and Closure
    • 2. Classes
    • 3. Private & Static
    • 4. UML Diagrams & Has Many/Belongs To Relationships
    • 5. Challenge: Implementing Has Many/Belongs To
    • 6. Inheritance
    • 7. Polymorphism
    • 8. Review and Practice
    • MDN: Object Prototypes
  • Mod 6 - Data Structures & Algorithms
    • Overview
    • Important How Tos and Guides
      • How to Debug
      • How to PEDAC
    • 1. Nodes & Linked Lists
    • 2. Singly & Doubly Linked Lists
    • 3. Stacks & Queues
    • 4. Recursion
    • 5. Trees
  • Mod 7 - React
    • Overview
    • Important How Tos and Guides
      • How to Create Projects with Vite
      • How to Deploy on GitHub Pages
    • 1. Intro to React
    • 2. Events, State, and Forms
    • 3. Fetching with useEffect
    • 4. React Router
    • 5. Building a Flashcards App
    • 6. React Context
    • 7. Global Context Pattern
  • Mod 8 - Backend
    • Overview
    • Important How Tos and Guides
      • How to Deploy on Render
      • How to Test your API with Postman
      • Postgres Setup
    • 1. Intro to Express
    • 2. Building a Static Web Server with Middleware
    • 3. Securing API Keys and Environment Variables
    • 4. RESTful CRUD API
    • 5. Model-View-Controller Architecture
    • 6. SQL and Databases
    • 7. JOIN (Association) SQL Queries
    • 8. Knex
    • 9. Your First Fullstack App!
    • 10. Migrations & Seeds
    • 11. Schema Design & Normalization
    • 12. Hashing Passwords with Bcrypt
    • 13. React Express Auth Template Overview
  • Mod 9 - Civic Tech Hackathon
    • Overview
    • Rubric
  • Mod 10 - Capstone
    • Overview
Powered by GitBook
On this page
  • What is the DOM?
  • The Chrome Developer Tools
  • The document object
  • Selecting Elements in the DOM (Read)
  • Modifying Elements in the DOM (Update / Delete)
  • Creating Elements (Create)
  • Linking JS files to HTML
  • Variables are Added to the Global Namespace
  1. Mod 2 - HTML, CSS & the DOM

4. The Document Object Model (DOM) API

Previous3. Accessibility (a11y)Next5. Events

Last updated 6 months ago

Follow along with code examples !

Table of Contents

What is the DOM?

The DOM is the Document Object Model. It is representation of the HTML structure of your website in a JavaScript object format.

For example, consider this HTML:

<h3 id="main-list-heading">Wow a list!</h3>
<ul id='my-list'>
  <li class="special-item">Here's an item in the main list</li>
  <li>Oh wow another one in main list</li>
  <li>And main list item</li>
</ul>

The DOM would take the elements of this HTML structure and turn them into objects! (This is not actually happening in your code. This is just to demonstrate the idea.)

// <h3 id="main-list-heading">Wow a list!</h3>
const h3 = { 
  id: "main-list-heading", 
  textContent: "Wow a list!" 
}

/* 
<ul id='my-list'>
  <li class="special-item">Here's an item in the main list</li>
  <li>Oh wow another one in main list</li>
  <li>And main list item</li>
</ul>
*/
const ul = {
  id: "my-list",
  children: [
    {
      className: 'special-item',
      textContent: "here's an item in the main list"
    },
    {
      textContent: "Oh wow another one in main list"
    },
    {
      textContent: "And main list item"
    }
  ]
}

The browser automatically generates this document object model for us! As web developers, we can use this DOM to do so much!

The Chrome Developer Tools

Open with f12 or by right-clicking and selecting inspect.

The Chrome Developer Tools allow us to interact with the source code of the page.

  • Use the Elements tab to view and manually manipulate the DOM

  • Use the Console tab to view console.log messages printed from the JS and to dynamically manipulate the DOM

The document object

The document object is the DOM packaged in an object. The properties of the object allow us to access various elements of the DOM. Each element is a node in the document tree and each node has a .children array.

Open the Console tab for this page and enter these expressions to see the objects returned:

document
document.children // [<html>]
document.children[0]              
document.children[0].children // [<head>, <body>]
document.children[0].children[0]  
document.children[0].children[1]

The document object also has methods that allow us to perform CRUD operations on the DOM:

  • Create new elements (create new "nodes" in the tree)

  • Read (find or "query for") existing elements

  • Update existing elements

  • Delete existing elements

Selecting Elements in the DOM (Read)

There are many ways to find an Element in the DOM, but querySelector is the most flexible. It uses CSS selector syntax

// returns the first h2 tag Element in the document
document.querySelector('h2');

// returns the all h2 tag Element in the document
document.querySelectorAll('h2');

// returns the first Element with the class font-semibold
document.querySelector('.font-semibold');

// returns all Elements with the class font-semibold
document.querySelectorAll('.font-semibold');

// get the Element with the id what-is-the-dom
document.querySelector('#what-is-the-dom');

// get the second span Element inside a code Element
document.querySelector("code > span:nth-child(2)")

It is important to note that querySelectorAll returns a NodeList which is NOT an array. You can use bracket notation but you can't use normal Array methods.

// codeBlocks is a `NodeList` which is like an array in many ways
const codeBlocks = document.querySelectorAll('code');

// We can access values with bracket notation
codeBlocks[0]

// forEach works too!
codeBlocks.forEach((block) => {
  block.style.backgroundColor = 'lightblue';
})

// But other methods dont... --> ERROR: codeBlocks.slice is not a function
codeBlocks.slice(0, 2);

// We can spread the contents into an Array first
[...codeBlocks].slice(0,5).forEach((block) => {
  block.style.backgroundColor = 'lightgreen';
})

Modifying Elements in the DOM (Update / Delete)

Once an Element is grabbed from the DOM, we can modify it, and even delete it!

const heading = document.querySelector('h1');
heading.textContent = 'The DOOOOM!';
heading.id = 'blahblah';
heading.classList.add('hello');
heading.classList.remove('font-bold')

// we don't always need to store the element in a variable to do something with it
document.querySelector("h1").remove();

Creating Elements (Create)

Using the DOM API to dynamically create elements is one of the most powerful ways we can use it!

The pattern:

  1. Create: const newEl = document.createElement('div')

  2. Modify: add an id, class, and text, whatever

  3. Add: parentEl.append(newEl)

// 1. Create
const newP = document.createElement('p');

// 2. Modify
newP.innerText = 'i love coding!';
newP.style.backgroundColor = 'orange';
newP.classList.add('font-bold');

// 3. Add
const body = document.querySelector('body'); // the parent
body.append(newP);

You can also insert HTML directly using .innerHTML but you should be very careful about doing this. Only ever do this if the content you are adding is hard-coded (not user-generated).

document.querySelector('body').innerHTML = `
  <li>coding</li>
  <li>basketball</li>
  <li>soccer</li>
`;

Linking JS files to HTML

Playing around with the document object in the Console shows us the power of the DOM API.

If we want to utilize this functionality in our own websites, we need to link a .js file to our HTML.

The most straightforward way to do this is to put a script tag at the bottom of your HTML document, typically at the end of the body, after the Elements of the document have been added to the page.

<body>
  <!-- Other html code must be added to the page before our script -->
  <!-- Put this just before the end of the body -->
  <script src="./index.js"></script>
</body>

In that index.js file, place a console.log statement and view it in the Console tab of the Chrome Developer Tools each time you reload the webpage.

Try the following code:

document.querySelector("#main-heading").textContent = "Hey!!!"

const body = document.querySelector('body')
body.style.backgroundColor = 'gold';
body.style.color = 'royalblue';

Q: Why does the script tag need to go at the end of the body?

This lets us do some really cool stuff, like dynamically creating elements from an array of data!

const addMovies = (movies) => {
  const moviesList = document.querySelector('#movies-list')

  movies.forEach((movie) => {
    const li = document.createElement('li');
    const thumbnailImg = document.createElement('img');
    const titleYearH3 = document.createElement('h3');
    const genresP = document.createElement('p');

    thumbnailImg.src = movie.thumbnail;
    thumbnailImg.alt = `Movie poster for ${movie.title}`;
    titleYearH3.textContent = `${movie.title} (${movie.year})`
    genresP.textContent = movie.genres.join(', ');

    li.append(thumbnailImg, titleYearH3, genresP);
    moviesList.append(li);
  });
}

The code above, creates the following li structure for every movie in the movies array:

<li>
  <h3>The Grudge (2020)</h3>
  <img src="thumbnail.jpg" alt="Movie poster for The Grudge">
  <p>Horror, Supernatural</p>
</li>

Variables are Added to the Global Namespace

When loading multiple .js files with script tags, variables declared are added to the global namespace. This just means that they are available in all subsequent .js files.

<body>
  <!-- if movies.js declares a variable called movies -->
  <script src="./movies.js"></script>
  <!-- that value is accessible inside of index.js -->
  <script src="./index.js"></script>
</body>

Back in the day, this was a useful feature as it let us keep our files separate but still be able to interact with each other since exporting and importing values wasn't invented yet.

Q: What are the risks of adding variables to the global namespace?

Adding variables to the global namespace is not ideal as it limits our ability to keep our files modular, leads to unexpected behavior, and makes debugging incredibly difficult.

Imagine you have an array stored in a variable named data in one file. In another file you write data.sort(), thinking that you are modifying a local variable but instead you end up modifying the data variable in the global namespace. In the first file, all of a sudden, your data is sorted unexpectedly without any logic that would explicitly do so in that same file.

To avoid adding variables to the global namespace, there are a couple of things we can do.

Option 1 — Use an IIFE (the old way)

One option is to always wrap the entire file in a top-level Immediately Invoked Function Expression (IIFE). An IIFE is an anonymous function that is immediately invoked. Since it is anonymous, there is no function name added to the global namespace. It is immediately invoked allowing the code inside to be executed.

(() => {
  const data = [];
})()

But then we lose the ability to share variables across files. If we want to share values across files, we need to be able to export and import values.

Option 2 — Use Modules (the modern way)

To enable exporting and importing, we can turn our file into a module by adding the type="module" attribute to the script tag:

<body>
  <script type="module" src="./movies.js"></script>
  <script type="module" src="./index.js"></script>
</body>

This enables ES6 importing and exporting syntax:

movies.js
const movies = [
  {},
  {},
  {},
]
export default movies;

Above, we use the export default syntax to export the movies variable from movies.js. Below, we import that value using the import...from syntax

index.js
import movies from './movies.js';

If we try this, we will end up with an error in our Console:

Access to script at 'file:///home/file/path/to/your/director/movies.js' from origin 'null' has been blocked
by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome,
chrome-extension, chrome-untrusted, https.

This is because of an unfortunate fact: browsers simply do not allow modules to be used over the file:// protocol. In order to use modules, we need to serve the modules via the http:// protocol.

Doing so means we need to turn our computer into a server!

More Reading:

More Reading:

But have no fear, this is actually quite easy. Just download the VS Code extension. A "Go Live" button will appear in the bottom right hand corner of your IDE. Just open the file you want to serve and click "Go Live" and voila — the file will be served via the http:// protocol instead of file://!

w3Schools
w3Schools
Live Server
here
What is the DOM?
The Chrome Developer Tools
The document object
Selecting Elements in the DOM (Read)
Modifying Elements in the DOM (Update / Delete)
Creating Elements (Create)
Linking JS files to HTML
Variables are Added to the Global Namespace
Option 1 — Use an IIFE (the old way)
Option 2 — Use Modules (the modern way)
The Live Server extension makes it easy to serve your HTML files via HTTP