DOM and Events
Last updated
Last updated
Define what DOM stands for and what it refers to
Select elements from the DOM using selectors
Add events to elements in the DOM
When the broswer loads a webpage, it takes in all the information about what needs to be displayed on the page, and creates a bunch of Javascript objects that represent the elements on the page. These objects mirror the html hierarchy, where the highest order parent is the document object.
Document Object Model: A model of all the html elements on a web page - usually represented by a tree of nodes - that is created by the browser when a web page is loaded.
Visit this website and open up the dev tools. Look at the Elements tab. Try expanding the collapsed elements to explore the structure of the document more. Now go to the Console tab and run document
to see the document object. Notice that this is the same hierarchy from the Elements tab. The Elements tab of the console shows us a vertical representation of the DOM
Now draw out a diagram (tree of nodes) that represents the DOM that is loaded by this webpage.
Clone the dom-practice repo.
Let's quickly review the boilerplate together.
Look at the <script>
tag. It includes main.js
in the <head>
:
The defer
attribute ensures the DOM is ready before the script executes.
Let's add an <h1>
inside of the <body>
as follows:
Note: It's a best practice to use double quotes and kebob-casing in the HTML.
Click on the Elements tab to browse the DOM.
To try it out, first select the h1
element and use the Styles panel to add a CSS property of color: red;
Look closely after the closing </h1>
tag - you see that == $0
?
That tells us that Chrome has created a variable named $0
that represents the <h1>
element in the DOM!
Click on the Console tab and let's explore the properties on the $0
object by typing dir($0)
.
Now try typing this in: $0.style.backgroundColor = 'yellow'
Now that's what I call a DOM!
Using Javascript, we can read and/or change the DOM, i.e. make the webpage do something interesting. That's the fun part of JS!
Examples:
Change or Remove HTML elements
Create and Add HTML elements
Change the CSS styles of HTML elements
Read & Change attributes of HTML elements (href, src, alt, etc)
Attach event listeners to HTML elements (click, keypress, submit, etc.)
Without DOM manipulation, web pages would just be static visuals with no changes and no interaction with the user.
Example:
Clicking on buttons would do nothing
You could never type into an input field
You could never zoom into an image or stop/start a video
The document object represents the DOM. It has several methods available to help us grab specific elements!
document.getElementById
document.getElementsByClassName
document.getElementsByTagName
html
css
js
Try using the id
to console.log
the first div
. What document
method did you use?
querySelector
methods allow us to use CSS Selector syntax to grab DOM objects.
document.querySelector
document.querySelectorAll
js
changing styles
single DOM element changes
Also available is textContent
that will retrieve or set content as plain text:
What if I want to do something to both divs at once?
Be Careful! Multi-element selectors like querySelectorAll
, getElementsByTagName
, and getElementsByClassName
don't actually return an array; they return something called an HTML collection. This means that many array methods (iterators, in particular, which we'll learn about later) wont work. If you run into this problem, you can use the Array.from
method to convert it to an array.
Accessing and changing element attributes
What if I want to change an attribute, like the src on this img?
html
There are 2 ways to get and set attributes of a DOM element. You can access the properties directly or use use get/setAttribute methods. It's important that you know both exist, but generally accessing the properties directly is more consistent across browsers.
Classes
Acessing, getting, setting CSS classes is slightly different than other properties.
First you can directly access the class attribute by using the className
property of a DOM element.
This works fine, but since elements can have multiple classes (separated by spaces) this often leads to needing to do some string parsing, so intead, we often use the classList
attribute, which gives us "a DOM token list".
And just like the HTML collection, we can access the values in the classList like an array.
You can add to the classList:
You can also check if an item has a class (returns true or false)
You can remove a class from the classList:
DOM events are the bedrock of interactivity on web pages. They enable us as developers to implement event-driven programming. This programming paradigm is such that much of our code, written as event listeners, runs in response to events being triggered during run-time.
Lots of events are generated within the browser, for example, when:
a user moves or clicks the mouse
a user presses a key
when a form is submitted
when the page has finished loading or has been resized
etc.
Take a gander here at the type and sheer number of events.
All of the selectors we've been using rely on the use of DOM elements. However, if the JavaScript loads before all the DOM elements load, the selectors won't recognize that some of them exist! To avoid this problem, there's an event called DOMContentLoaded
that we can encapsulate our code inside. Then, we can guarantee that the DOM elements exist before manipulating them.
An event listener is a function, more specifically, a callback function, that is called when an event fires. You may also hear them referred to as event handlers (depending upon how they are "registered" with the browser).
There are three different approaches for attaching event listeners to elements:
In the HTML (inline) - <button id="reset-btn" onclick="reset()">
- this isn't great because it embeds JavaScript code into our HTML, violating our separation of concerns.
Assigning to DOM elements' properties - resetBtn.onclick = reset;
- this is a better choice but it is limited to adding single event listeners.
Calling addEventListener
on a DOM element - this is the preferred way to do it since it is functional and supports adding multiple listeners at a time.
addEventListener([event type],[function that you want to run when the event fires])
It's possible to remove an added event listener, however, only if a named function was used as the callback:
Research a different event listener (not click
) and apply it to one of the divs
. Share your code in slack when you're done!
The first parameter to addEventListener
is the name of the event that we are listening for (e.g. click, change, keydown, etc.). The second parameter is the callback function that we pass in to tell the browser what to do when this event occurs. This callback is allowed to use a very special parameter: the event object (shown above as the parameter event
but is frequently abbreviated to evt
or e
).
This event object is passed into our event listener callback by the JavaScript engine in the browser. It contains may useful details about the event. Of special note are:
event.target
- this contains a reference to the actual DOM element that generated the event. In the case of a 'click' event, event.target
would be the element that was clicked on.
Several ...X and ...Y properties that tell where the click occurred.
event.preventDefault()
- a function to immediately disable the default action of this event for the given element. Useful for preventing unwanted form submissions or link navigation.
event.stopPropagation()
- a function for disabling the "bubbling" of this event up the DOM. More on this below...
Note: JavaScript's this
keyword within the listener function will also be set to the DOM element that addEventListener
was called on, so you can use it instead of event.target
if you like.
When an event occurs on an element, that event, whether it is listened to on that element or not, bubbles up through the DOM, all the way up to the document
object.
All event listeners registered for the same event, such as click
, will be invoked along the path to the document
element - unless one of those listeners calls the event object's stopPropagation()
method.
This passing of the event up the DOM tree allows for a very nice feature called Event Delegation.
Imagine an unordered list with many list items inside it. Each list item in our app needs to have a click event that allows it to perform some unique action. We could probably add an event listener to each list item and if there weren't too many, it woudn't be too bad. But imagine that this unordered list can grow and add hundreds of additional list items programmatically while the app is running. We can't add them to each element manually. Instead, because of the bubbling of events, we can delegate the parent of the list items to handle the event.
Event delegation allows us to register a single event listener that can respond to events triggered by any of its descendants. Much more efficient!
All we would need to do is view the event.target
property of the event object to see what element was referenced there. This would be the child element that generated the event.