JS: DOM Manipulation II
Learning Goals
- Access values input by the user
- Use Chrome dev tools to explore the event object
- Manipulate elements that have been programmatically added to the DOM after page load
Vocabulary
Event
Any event which takes place in the DOM, these can be generated by users or the browser.Event Listener
A function invoked on a DOM node which fires theevent handler
when a specified event occurs on the node or its childrenEvent Handler
A function that will run when a specific event occursevent.target
The element that is the “target” of the event. For example, the element that is clicked on in a click event.
DOM Manipulation Based on User Interaction
DOM manipulation based on user interaction requires putting several pieces together which is challenging! We can break it down into 3 steps:
- Elements: Querying the elements we’ll need
- Event Listener: Adding the event listener
- Function: Creating the function that the event listener will trigger
It is valuable to pseudocode out the steps of what you’re trying to do before you try to do it in code. Work through the practice below to revisit what we learned in the Intro to DOM Manipulation lesson.
Warm Up
Work through the practice below to revisit what we learned in the Intro to DOM Manipulation lesson.
DOM manipulation based on user interaction requires putting several pieces together which is challenging! It is valuable to pseudocode out the steps of what you’re trying to do before you try to do it in code.
Fork this Add Box Codepen.
Objective:
- Users should be able to click on the “Add Box” button to add additional boxes to the page.
First plan it out:
- Looking at the existing HTML and CSS
- Pseudocoding the directions, as step-by-step as possible, that you want to give to the computer.
- What are the DOM elements that your JS will need to know about? What variable names will you use for them?
- What event do you want to be “listening” for? What element does that event need to happen on?
- What do you want to happen when the event occurs on the specified element? What will you name the function that holds that code?
Then code it out:
- Implement your ideas in code.
- One person should share their screen and drive while the other navigates.
- The navigator should be coding along on their machine as well.
Let’s pseudocode baby!
Everyone pseudocodes a little differently. Here’s one example of what that thought process and pseudocode might look like….
// Goal: clicks the button.....Add a box
// query button
// add event listener for "click" on button
// event listener will invoke addBox function
// addBox function should add a new box to the DOM.
// Can i copy the html for the box from the html file??
// innerText? innerHTML? insertAdjacentHTML? *maybe i need to check MDN
// wait, where on the dom am i adding the boxes?? *check html
// i can add the boxes to the <section>. i'll need to query that too...
Get User Input
We already know how to programmatically change text, html and styling on the DOM when users take various actions. But what about collecting data from the user?
Another property that some HTML elements have, particularly input elements, is value
.
We can use the .value
property available on an input
DOM element to get the value that a user has typed into it.
Explore
Follow the steps below to explore how .value
works!
- Open your dev tools and inspect this box, specifically, the input field below. What is its unique identifier?
- In the console, call
document.querySelector('#check-me');
- In the console. call
document.querySelector('#check-me').value;
- Type your favorite food into the input
- In the console. call
document.querySelector('#check-me').value;
When called, the .value
property on an input element will return the current value.
Paired Practice
Fork this Dinner Time codepen.
Now that we know that we can access the user input with the .value
property, we can actually change what is showing on the DOM based on what a user types in!
Use JavaScript to capture the input values when the user clicks the Make Dinner button and update the content of the page accordingly.
First think it through, break it down and plan it out.
User types in inputs then clicks Make Dinner. Values from the inputs become the new main dish, side dish and dessert text shown on the page.
Take a few minutes to ask yourself and pseudocode out:
- What are the DOM elements that your JS will need to know about? What variable names will you use for them?
- What event do you want to be “listening” for? What element does that event need to happen on?
- What do you want to happen when the event occurs on the specified element? What will you name the function that holds that code?
- When and how will you grab the values the user has typed in?
Now code it out. One person should screen share and drive, the other should navigate. Navigator can also be coding along on their machine.
One of the top misconceptions/mistakes we see students make is attempting to capture the value of an input while the input is empty. If you want to get a user’s input, we have to get the value after the user has entered it. We do this by accessing the .value
property via some event listener - on an event that happens after the user has typed into the input field - like clicking Submit after filling out a form.
Thinking Ahead:
- What if you wanted to invoke 3 functions in a row on button click?
- What if you need to use logic to determine which function should be invoked on an event?
- Is it ok to have logic written out within our event listeners? Why? Why not?
- What if we need to pass an argument to the function we’re invoking in our event listeners?
- Why should we save our queried elements to variables? Why don’t we just type out the query selector when we need to access that variable?
Event.target
We’ve already explored the many times of events that can occur on our webpages and applications. Let’s dig a little deeper into the event
itself - regardless of which type.
Let’s go back to our Add Box codepen from the warmup and add another feature together.
Objective:
Users should be able to click on any of the boxes they’ve added and see that box change from gray to purple.
First think it through, break it down and plan it out.
After user adds more boxes…clicks any box…that box turns purple…
Take a few minutes to ask yourself and pseudocode out:
- What are the DOM elements that your JS will need to know about? What variable names will you use for them?
- What event do you want to be “listening” for? What element does that event need to happen on?
- What do you want to happen when the event occurs on the specified element? What will you name the function that holds that code?
Hm, usually we just use document.querySelector()
to grab the element we want to add the eventListener to. But the boxes are being dynamically added to the DOM when the user clicks the Add Box button. We can’t grab them using document.querySelector()
because they don’t exist yet when the files load. We’ll have to use a workaround approach that leverages the event.target
.
What we can do is write code that says:
- “Listen” for a “click” within the entire <section> that the boxes live in…
- When a click happens within that section, figure out which box was clicked on…
- Turn that box purple by adding the “purple” class that’s already styled in the CSS file
Step 1: “Listen” for a “click” within the entire section that the boxes live in
- Query the <section> and save to a variable
- Add eventListener to the <section> which will listen for a “click” and invoke a changeColor function
- Build the changeColor function skeleton (we’ll add the guts of the function later)
Step 2: When a click happens within that section, figure out which box was clicked on…
Ok…but, how??
- In the changeColor function, console log the keyword “event”
- Open the dev console and click one of the boxes to see the event print to the console
- Woooooow! Use the dropdown arrow to dig deeper into the event.
Complete this Scavenger Hunt, jotting the answers in your notes:
- What is the event type?
- What is the target of the event?
- If we dig into that target’s classList, what class(es) does the classList contain?
- Open the DOMTokenList dropdown within the target’s classList.
- What are some built in methods we could run on the target’s classList property? List 3 you might find useful.
- Does the target have an id?
- What is the target’s innerText?
- What is the target’s innerHTML?
- What is the parentNode of the target?
- What is the target’s previousElementSibling?
- What is the target’s nextElementSibling?
- Add another console log that prints the
event.target
Now that we know about event.target
, we can use that to access whichever box was clicked on.
Step 3: Turn the clicked-on box purple by adding the “purple” class that is already styled in the CSS file
- Within the changeColor() function, add the “purple” class to the event.target’s classList
Uh-oh! What happens if we click in the <section>
but not on one of the boxes? That’s not what we want to happen.
What logic can we add to our changeColor() function so that it only adds the purple class to the classList if the target of the click is one of the boxes?
Every box has the class “box”. Maybe we can use code to say: “if the element that was clicked on has the “box” class contained in its classList….then add the purple class”
Possible Solution:
let addBoxButton = document.querySelector('#addBoxButton')
let boxSection = document.querySelector('#boxSection')
addBoxButton.addEventListener('click', addBox)
boxSection.addEventListener('click', changeColor)
function addBox() {
boxSection.innerHTML += "<div class='box'></div>"
}
function changeColor() {
console.log('event: ', event)
if (event.target.classList.contains('box')) {
event.target.classList.add('purple')
}
}
More Practice - Get Weird
- What if we want to toggle between gray and purple on each click?
- What if in addition to turning it purple, we wanted to add the text “Hi!” inside the box when it gets clicked?
- What if we wanted to have a user click a box and have the box right BEFORE it turn purple instead?
- What if we wanted to have a user click a box and have the box that is TWO boxes AFTER it turn purple instead?
Key Takeaways:
- You can console log the event to get visibility into its many properties and their build in methods.
- We can use dot notation to access these properties and run the built in methods.
- Each DOM element has a classList with methods for .add(), .remove(), .contains(), .toggle()
- When a user takes an action, that action is an “event” and the “target” of that event is whatever element it happened on. We can access it via
event.target
. - querySelectors run on page load so you can’t just use document.querySelector to grab an element that is programmatically added to the DOM. Because it isn’t part of the initial HTML and doesn’t exist yet on page load.
- Instead, you’ll add an event listener to it’s parent container then use logic to execute your desired code if the event.target is one of the element you care about.
- This is all related to the concepts of event delegation and event bubbling. Not essential to dig into now but something you’ll want to google and learn about down the road. Maybe as interview prep.
Circling Back:
- What if you wanted to invoke 3 functions in a row on button click?
- Create a handler function that invokes all 3, invoke the handler function in your event listener
- What if you need to use logic to determine which function should be invoked on an event?
- We can add whatever logic we want to the functions that our event handlers run.
- Is it ok to have logic written out within our event listeners? Why? Why not?
- We want event listeners to simply and cleanly invoke one function and remain logic-free.
- What if we need to pass an argument to the function we’re invoking in our event listeners?
- We can open an anonymous function that invokes our event handler function and passes it an argument.
- Why should we save our queried elements to variables? Why don’t we just type out the query selector when we need to access that variable?
- Keeping them neatly stored in variables at the top of our file keeps our code readable and maintainable. Plus it ensure we aren’t repetitively querying the same element.
Check For Understanding
Recap
- What are 3 steps required when doing DOM manipulation based on user interaction?
- How do you access the values a user has entered?
- What is the preferred way to change styles programmatically?
- How do you access the element that a click event (or other type of event) occurred on?
- How do you access and manipulate elements that have been dynamically added to the DOM (since you can’t use a simple querySelector)?
Suggested re-teaching practice
- Work through the exercises in this legacy front end lesson on Event Bubbling and Event Delegation
- Create a codepen with an HTML form that collects to-do list info: task, priority level, description. When the user enters info and submits the form, create a litte “card” of that info and display it on the DOM. For an added challenge, add functionality to delete the task card if the user double clicks it.
- Read up on the event listener documentation