Event Bubbling and Delegation PDF
Document Details
Uploaded by DazzledChaparral
Howest
Tags
Summary
This document explains event bubbling and delegation in JavaScript. It details how events propagate through the DOM tree and how to control event propagation. It provides examples and detailed explanations to aid in understanding this important concept.
Full Transcript
BEFORE WE START F O R T H I S C O U R S E FINAL NEW TOPIC! Yay! FOR THOSE OF YOU THAT NEED CERTAIN TOPICS REVISITED https://leho-howest.instructure.com/courses/24628/pages/digital-alternative? module_item_id=903472 EVENT BUBBLING ...
BEFORE WE START F O R T H I S C O U R S E FINAL NEW TOPIC! Yay! FOR THOSE OF YOU THAT NEED CERTAIN TOPICS REVISITED https://leho-howest.instructure.com/courses/24628/pages/digital-alternative? module_item_id=903472 EVENT BUBBLING F R O M C H I L D T O P A R E N T EVENT BUBBLING Event Bubbling is a form of event propagation in which when an event fires on the innermost element, it is subsequently fired for each of its parents, all the way to the root element. We say the event "bubbles up" (or propagated) to all ancestors F R O M C H I L D T O P A R E N T E V E N T S B U B B L E B Y D E FA U LT The default behaviour of an event is that it bubbles outwards, all the way to the top of the DOM tree, triggering that same event on all of its parents. https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/ Events#Event_bubbling_and_capture will trigger a click on body, all the way up will trigger a click on main Bubbling demonstration will trigger a click on section See this bubble! Click me to see the bubble! click on anchor IF THERE WOULD BE ASSOCIATED EVENT HANDLERS THEY WOULD BE TRIGGERED is triggered first document.addEventListener('DOMContentLoaded', init); next next function init() { document.querySelector('a').addEventListener('click', doSomething); document.querySelector('section').addEventListener('click', doSomethingElse); document.querySelector('main').addEventListener('click', doSomethingOnMain); document.querySelector('body').addEventListener('click', doSomethingOnBody); } finally F O U R F U N C T I O N S E X E C U T E D ONE CLICK, FOUR EVENTS TRIGGERED! A single click caused four event handlers to trigger. If there are no event handlers bound to a certain parent element, nothing happens, but if they are, be aware that this is standard behaviour! DEMO F R O M C H I L D T O P A R E N T WHAT IF YOU WANT TO STOP BUBBLING? There may be situations, where you have several handlers applied to elements in an hierarchical structure, but you do not wish for one to trigger the other e.g. clicking on an "add to favourite" link inside an article that links to the detail page clicking this you do not want to see the adds the item detailed product view when to "favourites" adding this item to your favourites the entire article has a click event bound to it, taking the user to a detail view of the product A L L T H E W A Y U P T H E C H A I N STO PPR O PAG AT I O N ( ) This method prevents further propagation of the current event. It does not, however, prevent any default behaviours from occurring; for instance, clicks on links are still processed. If you want to stop those behaviours, you will still need to implement the preventDefault() method. SHORTHAND EXAMPLE Click me to see the bubble! is triggered first document.querySelector('a').addEventListener('click',doSomething); document.querySelector('p').addEventListener('click',doSomethingElse); function doSomething(e){ e.preventDefault(); console.log('clicked the anchor'); } function doSomethingElse(e){console.log('clicked the p');} is triggered next *DOMContentLoaded omitted for readability NOW IF WE STOP THE EVENT FROM BUBBLING Click me to see the bubble! document.querySelector('a').addEventListener('click',doSomething); document.querySelector('p').addEventListener('click',doSomethingElse); function doSomething(e){ e.preventDefault(); e.stopPropagation(); will stop triggering further any handlers in ancestral line console.log('clicked the anchor'); } function doSomethingElse(e){console.log('clicked the p');} *DOMContentLoaded omitted for readability is never called when clicking on a DEMO WHAT IF… There are two handlers of the same event type on the same element? USE CASE F R O M C H I L D T O P A R E N T ANOTHER USE CASE Another common use case for this is when developing front end modules that bind events on both same level as well as higher up objects (e.g. window) that may interfere with one another. You may want to stop the others being called. Be cautious when using this function: it will not only stop the triggering of other events on that element, but will also kill any bubbling that is in place will both be triggered on click, in the order of binding Click me to see the bubble! document.querySelector('a').addEventListener('click',doSomething); document.querySelector('a').addEventListener('click',doSomethingElse); function doSomething(e){ e.preventDefault(); console.log('clicked the anchor'); } function doSomethingElse(e){console.log('anchor different functionality');} *DOMContentLoaded omitted for readability Click me to see the bubble! document.querySelector('a').addEventListener('click',doSomething); document.querySelector('a').addEventListener('click',doSomethingElse); function doSomething(e){ e.preventDefault(); prevents doSomethingElse() from e.stopImmediatePropagation(); console.log('clicked the anchor'); being invoked } function doSomethingElse(e){console.log('anchor different functionality');} *DOMContentLoaded omitted for readability will not be called Click me to see the bubble! document.querySelector('a').addEventListener('click',doSomething); document.querySelector('a').addEventListener('click',doSomethingElse); document.querySelector('body').addEventListener('click', doSomethingOnBody); function doSomething(e){ e.preventDefault(); also prevents doSomethingOnBody() e.stopImmediatePropagation(); console.log('clicked the anchor'); from being invoked } function doSomethingElse(e){console.log('anchor different functionality');} function doSomethingOnBody(e) {console.log('clicked on the body');} will not be called *DOMContentLoaded omitted for readability S I D E W A Y S A N D A L L T H E W A Y U P T H E C H A I N STO PI M M E D I AT E PR O PAG AT I O N ( ) This method prevents other listeners of the same event from being called. If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. If stopImmediatePropagation() is invoked during one such call, no remaining listeners will be called, not even in an ancestral line.stopPropagation().stopImmediatePropagation() Allows listeners on the same element of the same type to fire YES NO Allows listeners of the same type to fire on parent elements NO NO DEMO EVENT CAPTURING WHAT IF… You want to bubble… from the outside in? F R O M P A R E N T T O C H I L D EVENT CAPTURING Event capturing is an alternative form of event propagation, similar to event bubbling, but with the order reversed. Instead of the event firing first on the innermost element, and then on successively less nested elements, the event fires first on the least nested element (parent), and then on successively more nested elements, until the target is reached. HOW? by adding a third parameter, true, to the.addEventListener() method. document.querySelector('a').addEventListener('click',doSomething, true); SHORTHAND EXAMPLE Click me to see the bubble! document.querySelector('a').addEventListener('click',doSomething, true); document.querySelector('p').addEventListener('click',doSomethingElse, true); function doSomething(e){ e.preventDefault(); then this console.log('clicked the anchor'); } function doSomethingElse(e){console.log('clicked the p');} *DOMContentLoaded omitted for readability this will be executed first U N C O M M O N P A T T E R N USE WITH CAUTION! Be mindful when implementing this, only do so when absolutely necessary because you're reversing an assumed order of events in the minds of the developers. When you do, clearly state why you are implementing capturing, rather than bubbling. Also: we advise, If possible, to fully list the chain of events captured in order to avoid confusion. It will work if you don’t, but it’s better for everyone’s sanity if you do. DEMO MORE EXPLAINED https://javascript.info/bubbling-and-capturing EVENT OBJECT REVISITED WHAT IF… You want to know which child triggered the event.. but also which parent caught it? W H A T ' S T H E D I F F E R E N C E ? E.CURRENTTARGET VS E.TARGET e.target e.currentTarget the element which the element on which the originated the event event was bound (which has the event handler bound to it) BINDING THE EVENT ON THE A Click me document.addEventListener('DOMContentLoaded',init); function init(){ document.querySelector('a').addEventListener('click',doSomething); } function doSomething(e){ e.preventDefault(); console.log(e.target); console.log(e.currentTarget); } B I N D I N G T H E EVE N T O N T H E PA R E N T Click me document.addEventListener('DOMContentLoaded',init); function init(){ there is no event handler on ! document.querySelector('div').addEventListener('click',doSomething); } function doSomething(e){ e.preventDefault(); console.log(e.target); this is the inner most console.log(e.currentTarget); element that was clicked } DEMO WHY DO WE NEED ALL OF THIS? T H E B A C K B O N E O F W E B A P P L I C A T I O N S DYNAMIC DATA The content of your applications will be largely dynamically populated. We'll request some information from the server (through an API), which in turn will consult some form of data storage (e.g. database) which will then send us back the data we are looking for request request response response client data store server B L A C K A N D W H I T E , W I L L R E Q U I R E N U A N C I N G L A T E R DEFINITIONS static data dynamic data computed data data that is data that originates from data that is calculated / present in a data store and is parsed / computed live on the HTML injected into the HTML the page and updated by and is through JavaScript means of events, but not unchanging retrieved from a data store dynamic data also dynamic data static data static data dynamic data also dynamic data static data also dynamic data static data dynamic data AN EXAMPLE CLOSER TO HOME dynamic data static data static data A N D T H E C O N S E Q U E N C E S INSERTING DYNAMIC DATA When you dynamically insert new data into the DOM, all previously bound event handlers are gone! DEMO H OW D O WE S O LVE T H I S? C O M M O N P R A C T I C E I N W E B D E V E L O P M E N T EVENT DELEGATION Event delegation is the practice of having an ancestor handle the events of its children, deliberately letting the event bubble up from the children to the parent. The most common use cases for this are: - when many of the children's events should be handled in the same manner - when dealing with dynamic data *querySelector for readability document.querySelector('.people li') Jane Doe.addEventListener('click',selectPerson); Johnny Fever Jack Brick function selectPerson(e){ James McQueen // Select a person and do something with it Randall Wise console.log('clicked ', e.target); Lydia Flynn } *DOMContentLoaded omitted for readability *querySelector for readability document.querySelector('.people li').addEventListener('click',selectPerson); function selectPerson(e){ // Select a person and do something with it console.log('clicked ', e.target); } function fillPeople(){ // populates the list //... } *DOMContentLoaded omitted for readability const people = ['Jane Doe', 'Johnny Fever', 'Jack Brick']; document.addEventListener('DOMContentLoaded',init); function init(){ Jane Doe document.querySelector('.people li').addEventListener('click',selectPerson); fillPeople(); Johnny Fever } Jack Brick>/li> function selectPerson(e){ // Select a person and do something with it console.log('clicked ', e.target); } function fillPeople(){ people.forEach((person) => { document.querySelector('.people').insertAdjacentHTML('beforeend', `${person}`); }); } *document.querySelector would be better outside the loop for performance reasons, but not the focus of this topic const people = ['Jane Doe', 'Johnny Fever', 'Jack Brick']; document.addEventListener('DOMContentLoaded',init); function init(){ document.querySelector('.people li').addEventListener('click',selectPerson); fillPeople(); } but! click event will no longer work, was bound function selectPerson(e){ // Selectbefore new a person and elements were do something withinjected it into the console.log('clicked ', e.target); } DOM function fillPeople(){ people.forEach((person) => { document.querySelector('.people').insertAdjacentHTML('beforeend', `${person}`); }); } *document.querySelector would be better outside the loop for performance reasons, but not the focus of this topic const people = ['Jane Doe', 'Johnny Fever', 'Jack Brick']; document.addEventListener('DOMContentLoaded',init); function init(){ document.querySelector('.people').addEventListener('click',selectPerson); fillPeople(); } function selectPerson(e){ solution: bind to the list instead of the li, // Select a person and do something with it this is always present in console.log('clicked ', e.target); the DOM } function fillPeople(){ Note: binding deliberately with people.forEach((person) => {querySelector, there is only a single document.querySelector('.people') element!.insertAdjacentHTML('beforeend', `${person}`); }); } *document.querySelector would be better outside the loop for performance reasons, but not the focus of this topic const people = ['Jane Doe', 'Johnny Fever', 'Jack Brick']; document.addEventListener('DOMContentLoaded',init); function init(){ document.querySelector('.people').addEventListener('click',selectPerson); fillPeople(); } function selectPerson(e){ // Select a person and do something with it console.log('clicked ', e.target); } some magic will be needed in here though function fillPeople(){ people.forEach((person) => { document.querySelector('.people').insertAdjacentHTML('beforeend', `${person}`); }); } *document.querySelector would be better outside the loop for performance reasons, but not the focus of this topic LET'S SEE THE MAGIC IN A DEMO Y E T S E E N A L O T … BAD PRACTICE Common practice for people with (little to) no understanding of event binding is the following: // Function which dynamically inserts data function fillPeople(){ people.forEach((person) => { document.querySelector('.people').insertAdjacentHTML('beforeend', `${person}`); }); document.querySelectorAll(‘.people li’).forEach(($dynamicListItem) => { $dynamicListItem.addEventListener('click', doSomething); }); } * follows previous example never do this! E S P E C I A L L Y W H E N U S I N G D Y N A M I C D A T A A LWAYS D E L E G AT E WH E N N E C E S S A RY ! It is bad practice to rebind all lost events in a hard-coded manner. Doing so in your project (instead of using event delegation) or exam will negatively impact your score, considerably. DOM SCRIPTING A LITTLE TOO FAST FOR YOU? F L E X B O X O R I E N T E D ADDITIONAL GUIDED SESSION Still struggling with DOM scripting basics? Guided exercise session (Hacker Dashboard exercise): Tuesday November 19th, 13:30 - 15:00 in room BST.A.5.203 (60 seats available) EVENTS RECAP N O Y O U D O N ' T H A V E T O K N O W T H E S E B Y H E A R T ! THERE ARE QUITE A FEW OF THEM https://developer.mozilla.org/en-US/docs/Web/Events Take the time to familiarise yourself with the most common ones. We will apply some in the practicum sessions, but you may need additional ones in the project N O O T H E R W A Y THEY ARE BOUND IN CODE Always use.addEventListener method to bind events to your element. Also, be mindful of which element they should be bound to. REMEMBER OUR 3 QUESTIONS 1) Which element triggers the event? 2) What type of event is it? 3) What needs to happen when the event occurs? SELECT THE ELEMENT THAT WILL FIRE THE EVENT document.querySelector('#shoppingcart') (1) Which element triggers the event? BIND THE CORRECT EVENT TYPE (2) What type of event is it? document.querySelector('#shoppingcart').addEventListener('click'); DETERMINE WHAT HAPPENS NEXT document.querySelector('#shoppingcart').addEventListener('click', displayCart); (3) what needs to happen when the event occurs? TWO STEP PROCESS Step 1: Wait until the DOM tree Step 2: Bind the event of has loaded in-memory choice to the element document.addEventListener('DOMContentLoaded', init); function init(){ document.querySelector('#book').addEventListener('click', makeReservation); } WANT TO ADD ANOTHER ONE? Repeat step 2: Bind the event of choice to the element document.addEventListener('DOMContentLoaded', init); function init(){ document.querySelector('#book').addEventListener('click', makeReservation); document.querySelector('#show-details').addEventListener('click', showDetails); document.querySelector('#login').addEventListener('submit', validateLogin); } WANT TO ADD ANOTHER ONE? Repeat step 2: Bind the event of choice to the element document.addEventListener('DOMContentLoaded', init); function init(){ document.querySelector('#book').addEventListener('click', makeReservation); document.querySelector('#show-details').addEventListener('click', showDetails); document.querySelector('#login').addEventListener('submit', validateLogin); } HTML element that event type event handler triggers the event CAREFUL WITH GOOGLE 1 2 3 different results 3 EVERY SINGLE ONE IS INCORRECT! result 1 window.onload !== domcontentready, wrong event!! old notation more old notation shorthand nested in an anonymous function WHAT 'S THE DIFFERENCE? document.addEventListener('DOMContentLoaded', init); window.addEventListener('load',init); https://javascript.info/onload-ondomcontentloaded result 2 this is jQuery, not JavaScript result 3 unobtrusive, JS in HTML, very bad idea LET 'S DIVE INTO MORE DETAIL ON HOW EVENTS WORK O R A T L E A S T N O T W H E N T H E Y W I L L H A P P E N EVENTS ARE OCCURRENCES WE CANNOT PREDICT We cannot say when a user will click a button, when a page finishes loading, when a form will be filled out,.... A S Y N C C O D I N G SO WE CREATE CODE THAT PROMISES TO WAIT FOR THE EVENT When the event does happen, i.e. when the event is triggered, the code associated with it, which was "waiting" to be executed, is executed. This makes events asynchronous in nature SYNCHRONOUS VS ASYNCHRONOUS first the interpreter executes this line then this line then the next THIS IS SYNCHRONOUS BEHAVIOUR When the order of writing matches the execution order these lines are executed synchronously yet we cannot know when this block of code will be executed, even though it is next in the code, there is no guarantee this code will be the next to be executed. previousNumbers() might be executed earlier, even though it is written later in the code THIS IS ASYNCHRONOUS BEHAVIOUR When the order of writing does not match the execution order SO YOU CANNOT WRITE DEPENDENT CODE document.addEventListener('DOMContentLoaded', init); let counter = 0; function init() { document.querySelector(‘a').addEventListener('click', doSomething); console.log(counter); // This will be 0 !! } function doSomething(e) { this block has not yet been called at the point of the e.preventDefault(); console.log() counter++; } NOR SHOULD YOU RETURN ANYTHING FROM AN EVENT HANDLER document.addEventListener('DOMContentLoaded', init); function init() { let counter = 0; document.querySelector('a').addEventListener('click', doSomething); counter += doSomething(); console.log(counter); } this doesn't work! function doSomething(e) { e.preventDefault(); return 1; } YOU *CAN* CALL ANOTHER FUNCTION FROM WITHIN THE EVENT HANDLER document.addEventListener('DOMContentLoaded', init); let previousNumbers = []; function init() { document.querySelector('#generate').addEventListener('click', showNumbers); } function showNumbers(e) { e.preventDefault(); showPreviousNumbers(); this is okay const lotteryNumbers = generateNumbers(); so is this render(lotteryNumbers, '#generated'); previousNumbers = lotteryNumbers; } function showPreviousNumbers() { if (previousNumbers.length > 0) { render(previousNumbers, '#previous'); } } THE EVENT OBJECT A N D Y O U G E T T O C H O O S E I T S N A M E E,EVENT,EVT Every event handler automatically gains an event object, which holds valuable information about the event. Most notably the caller, its parent(s), X an Y values on the screen,... https://developer.mozilla.org/en-US/docs/Web/API/Event document.addEventListener('DOMContentLoaded', init); function init() { document.querySelector('#generate').addEventListener('click', showNumbers); } function showNumbers(e) { this is the event object (you can choose its name) e.preventDefault(); showPreviousNumbers(); it has methods which can be invoked const lotteryNumbers = generateNumbers(); render(lotteryNumbers, '#generated'); previousNumbers = lotteryNumbers; } THE PREVENTDEFAULT METHOD C A N O N L Y B E I N V O K E D O N T H E E V E N T O B J E C T P R E V E N T D E FA U LT ( ) M E T H O D preventDefault() will stop the default behaviour of the element on which the event was triggered. Whatever its default behaviour when that event occurs would be, has now been cancelled. We will often do this to 'overwrite' unexpected behaviour, such as the page refreshing or the form submitting https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault Book stops this link from being followed document.querySelector('#book').addEventListener('click', book); function book(event){ event.preventDefault(); this code } Book in most of our examples, will stop the page jumping to the top document.querySelector('#book').addEventListener('click', book); function book(event){ event.preventDefault(); this code } W H Y N O T J U S T O M I T T H E H R E F A L L T O G E T H E R ? WH Y ST I L L M E N T I O N A PAG E I N H R E F ? For accessibility reasons it is imperative we try to make our applications work without JavaScript support. They will not work as well, but the basics should be in place. More on this next year! E.TARGET A L L I N S I D E I T S P R O P E R T I E S THE EVENT OBJECT CAN TELL US WHO INVOKED IT By accessing the target property (e.target) we obtain the element which triggered the event, and any information that element carries with it Wish list First element Second element Third element Fourth element Fifth element document.addEventListener('DOMContentLoaded',init); function init(){ let wishes = document.querySelectorAll('.wish'); wishes.forEach((wish) => { wish.addEventListener('click',showWhichOneWasClicked); }); } function showWhichOneWasClicked(e){ console.log(e.target); } Wish list First element Second element Third element Fourth element Fifth element document.addEventListener('DOMContentLoaded',init); function init(){ let wishes = document.querySelectorAll('.wish'); wishes.forEach((wish) => { wish.addEventListener('click',showWhichOneWasClicked); }); } function showWhichOneWasClicked(e){ console.log(e.target); } W H E N Y O U N E E D E V E N T S O N M O R E T H A N O N E E L E M E N T QUERYSELECTORALL Returns a list of nodes matching the specified group of selectors https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll DEMO HTML DATA ATTRIBUTES U S E F U L A S C O N T A I N E R S DATA ATTRIBUTES Data attributes provide us with a way to store data linked to an HTML element. Usually, this entails additional meta data we will need at a later time (after an event has been invoked) https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes we need to know in which semester these course occur in order to filter them later we need to know in which semester these course occur in order to filter them later C H O O S E T H E S U F F I X DATA-??? Data attributes are prefixed with "data-" and then a suffix of your choice is added. e.g. ๏ data-semester ๏ data-language ๏ data-id D A T A A T T R I B U T E S ACCESSING THROUGH JS Object Oriented Programming OOP 6SP Mattias De Wael You can access them with Reeds volbracht the.getAttribute() function or you can access them with the special.dataset collection. document.querySelector('article').dataset.semester; document.querySelector('article').getAttribute('data- semester'); https://developer.mozilla.org/en-US/ docs/Web/API/HTMLElement/dataset FUNCTIONS REVISITED FUNCTION DECLARATION There are different ways to write a function in JavaScript FUNCTION DECLARATION anonymous function arrow function named function function add (a){ function (a){ (a) => a + 100; return a + 100; return a + 100; } } FUNCTION DECLARATION named function document.querySelector('button').addEventListener('click',showMessage); function showMessage(e){ console.log('Ooh that tickles!'); } anonymous function document.querySelector('button').addEventListener('click', function showMessage(e){ console.log('Ooh that tickles!'); }); arrow function document.querySelector('button').addEventListener('click', (e) => console.log('Ooh that tickles!')); WHEN TO USE WHICH? named function anonymous function arrow function Your go-to for function Sometimes, what you're doing When anonymous is still too declarations. is so obvious and short, long for your liking, you can abstracting it into a separate shorten it with an arrow function would only result in function. 95% of the time, you'll be using a named function, of needlessly verbose code. reuse purposes as well as Next semester, we'll talk about legibility. When this is the case and the what additional impact this code will not be reused, go decision has on the "this" anonymous. variable. A function needs to do "something", and in order to describe "something", you need a name. Period. WHEN TO USE WHICH? named function anonymous function arrow function Your go-to for function Sometimes, what you're doing When anonymous is still too declarations. is so obvious and short, long for your liking, you can abstracting it into a separate shorten it with an arrow function would only result in function. 95% of the time, you'll be Make this your default Butverbose needlessly there code. is nothing wrong with using these using a named function, of reuse purposes as well as Next semester, we'll talk about legibility. When this is the case and the what additional impact this code will not be reused, go decision has on the "this" anonymous. variable. A function needs to do "something", and in order to describe "something", you need a name. Period. SOME COMMON USE CASES A LOT OF NEW INFORMATION Let’s review this session’s new information in some common use cases DEMO #1 How do I toggle between two states? Example use of e.preventDefault() DEMO #2 How do I dynamically add items to a list? Example use of e.target DEMO #3 Similar example, but with a different event and retrieve the data from HTML Example use of dataset DEMO #4 How do I capture data from a form? Example use of e.preventDefault() DOM TRAVERSAL AND MANIPULATION REVISITED SOME METHODS I WANTED TO HIGHLIGHT In light of this afternoon's exercise CLOSEST This function travels the DOM tree upwards to the nearest parent matching the given selector. const $parentElement = $element.closest("section"); Always favour this function over.parentNode. closest() is much more flexible and future proof will select this All outgoing traffic blocked h2> You have blocked all outgoing traffic, so even though you can't browse the web, you'll still be kept safe from harm. Good, right? p> I understand a> section> const $parentElement = $element.closest("section"); < / < / < / < / Even when the HTML changes All outgoing traffic blocked h2> You have blocked all outgoing traffic, so even though you can't browse the web, you'll still be kept safe from harm. Good, right? p> I understand a> div> section> const $parentElement = $element.closest("section"); will still match < / < / < / < / < / INNERTEXT VS TEXTCONTENT const $h1 = document.querySelector("h1"); textContent: will select all text in a console.log($h1.textContent); given element console.log($h1.innerText); innerText: will only select visible text test hidden span> h1> in a given element h1 span { Note: text must be hidden with display or display: none visibility property } < / < / DOM TRAVERSAL O F W H A T W E K N O W S O F A R SHORT RECAP I N D I F F E R E N T D I R E C T I O N S DOM TRAVERSAL Travelling up, down and sideways in the DOM tree, using DOM traversal methods or properties to access different HTML elements or attributes. QUERYSELECTOR This function takes a CSS selector as argument. (Remember, these were going to be important?) document.querySelector("li a"); This must be valid CSS syntax, or a SyntaxError exception will occur. It returns the first element that matches the selector. const linkText = document.querySelector("li a").innerText; We are here QUERYSELECTOR (2) You do not need to select agains the document, you can also select within a given parent element const $parent = document.querySelector('div'); const $spanInParent = $parent.querySelector('p span'); W I T H D O M M A N I P U L A T I O N WE CAN ALSO MAKE CHANGES T E R M I N O L O G Y DOM MANIPULATION The process of using the DOM modify the structure, style, or content of a web component. The browser offers a set of predefined methods and properties to allow these modifications. INNERHTML Modifies the value, allowing HTML elements as values as well. const $element = document.querySelector('main section h2'); $element.innerHTML = 'Different Title'; I N T O T H E P A G E WHAT IF I WANT TO INJECT LARGE B L O C K S O F H T M L? const name = 'Jane Doe'; const title = 'Personal profile'; let html = ''; html += '' + title + ' h1>'; html +='Hello there, ' + name + ' p>'; html +=' section>'; < / < / < / S O O L D S K O O L LET ’S NOT DO THAT string concatenation is painful and error prone TEMPLATE LITERALS T E M P L A T E L I T E R A L S F T W ! INSTEAD LET’S DO THIS matches with that const name = 'Jane Doe’; matches with that const title = ‘Personal profile'; let html = ` ${title} h1> this Hello there, ${name} p> section>`; and this < / < / < / S T R I N G C O N C A T I N A T I O N ’ S R E P L A C E M E N T TEMPLATE LITERALS Allow us to write strings with variables included and maintain easy- to-read formatting, allowing new lines without breaking the code const article = ` a> Astrobiologists shift their gaze h3>