I am creating this post as notes from Wes Bos Javascript course which you can sign up for and do with me here: https://beginnerjavascript.com/. Here is a link to Wes' GitHub readme.md.
If you haven't read part 1 of this series, check it out.
In DOM manipulation, a common thing to do is to add and remove classes. This is especially helpful when you want a click event or some action on the page to change the look and feel of a component.
classList
You can use the selection
methods we referred to in the last part of this series to select an object and then see the classes using a method called classList
. Within that you can even use more methods such as: add
, remove
, toggle
, & contains
.
toggle
will allow you to turn on/off a class without having to know the status. It will add the class if it's not there, remove it if it is. add
& remove
are pretty obvious but are not aware of the current state like toggle
Attributes
Attributes are anything added to an element that provides more information to the element. class
, href
, id
, src
, alt
, style
, etc... are all examples of attributes.
Custom Attributes
Thought I'd share something I wasn't aware was that in
alt
tags, it's unecessary to sayalt="Photo of thing"
because the screen reader already informs the user that it's a photo. This creates redundant information that could be shortened toalt="thing"
in this example.
Interesting things you can do with this:
const pic = document.querrySelector('img'); //Selects an img on the page pic.alt = 'Thing' //Allows you to add an alt tag "Thing" console.log(pic.getAttribute('alt'); //logs the alt tag for the img //You can also use this: pic.setAttribute('alt', 'This is a new alt tag'); console.log(pic.getAttribute('alt'); // "This is a new alt Tag"
Data Attributes
Custom Attributes are ones that are free form and don't necessarily follow a specific format/convention like the alt
tag mentioned above.
While you can do it, it's not recommended to creat your own custom attributes (which you can do from set attributes). Data attributes are a better use case for this.
data-name
(where name can be replaced with anything you'd like) is the preferred method over creating your own custom attributes because it's not going to be overwritten one day by updates to Javascript.
HTML from Strings and XSS
createElement();
const myParagraph = document.createElement('p');
is the most common method of creating HTML elements (this one specifically creates a <p></p>
element. You can use the attributes section above to add attributes to the element. While it's created, it won't show on the page because you will have to append it to the DOM.
Paint that created element on the page using appendChild();
document.body.appendChild(myParagraph);
would do this but add it at the end of the body tag. Note, when you do this, it will cause the browser to do what is called a "reflow", basically a page refresh. If you do this a lot, it can negatively affect the user experience. The way to work around this is to only call the document.body.appendChild(someTagYouMade)
once after appending the element you wanted to create that isn't on the page yet. That was a lot to chew on, let's break that down.
const myDiv = document.createElement('div'); myDiv.classList.add('containter'); document.body.appendChilde(myDiv); const myImage = document.createElement('img'); myImg.src = 'https://google.com'; myImg.alt = 'Cool Photo, Bruh'; document.body.appendChilde(myDiv); const myParagraph = document.createElement('p'); myParagraph.classList.add('specialPara'); myParagraph.textContent = 'I am a p tag'; document.body.appendChild(myDiv);
While you can do the above, it's not DRY (Don't Repeat Yourself). The better way to run this would be to create all the elements and their attributes then append to the body like this:
const myDiv = document.createElement('div'); myDiv.classList.add('containter'); const myImage = document.createElement('img'); myImg.src = 'https://google.com'; myImg.alt = 'Cool Photo, Bruh'; const myParagraph = document.createElement('p'); myParagraph.classList.add('specialPara'); myParagraph.textContent = 'I am a p tag'; document.body.appendChild(myDiv);
This is not only less code to write, but it's a better user experience because the browser doesn't have to repaint the page 3 times.
element.insertAdjecentElement(position, element);
Remember the insertAdjacentText();
like we used on part one? The convention for position is the same where you can use:
'beforebegin'
: Before theelement
itself.'afterbegin'
: Just inside theelement
, before its first child.'beforeend'
: Just inside theelement
, after its last child.'afterend'
: After theelement
itself.
<!--beforebegin
--><p>
<!--afterbegin
--> foo <!--beforeend
--></p>
<!--afterend
-->
element.cloneNode();
This method clones the node, since we haven't really tackled the tree structure of the DOM to explain the difference between parents, children, and nodes - let's dive into that really quick:
What you can see in the image above is the DOM Tree. This is completely fictious and just a visual representation of what happens in your browser. The DOM tree shows all the elements on the HTML and below them are the children. If you wanted to select the h1
tag it would be a child of body
and a parent of the text node
"DOM Lesson one".
What this method cloneNode()
does is clone the element you select but it won't clone it's children unless you pass an argument of true
like so: element.cloneNode(true);
.
Example:
//Clone h1 from the DOM tree above const heading = document.querySelector('h1'); heading.cloneNode();
What will happen in the example above is that it will copy that h1
tag but none of the text content inside - specifically "DOM Lesson one", you would accomplish that by running:
//Clone h1 from the DOM tree above const heading = document.querySelector('h1'); heading.cloneNode(true); //note we are going "DEEP" here
Creating HTML using strings
There are some security risks associated with doing this (XSS attacks, more on that in a moment)
Remember how I said there is a ton of benefits to the backticks in Javascript over the use of ""
or ''
? Well if you haven't read that article yet, its here: https://codingwithdrew.com/2019/12/12/javascript-backticks-and-nodejs/
In this section, we are going to learn aboutinnerHTML
which is a method of putting strings onto the DOM from javascript as long as they are valid HTML format. Let's take a look at this tool.
<html>
<header>
</header>
<body>
<div class="thing>
</div>
<script>const thing = document.querySelector('.thing');
thing.innerHTML = `
<h1>This is inside of backticks ;) </h1
>
<img src="https://someimageURL.com" alt"some image"><img>
<p> This is the power of backticks, multiline code that maintains,<br>
it's spacing!</p>
`;
</script>
</body>
</html>
Other interesting notes: in backticks you can actually pass Javascript variables using
`${putAVariableHere}`
which will unlock so many more cool things you can do with javascript like templating!
One important thing to point out is that these are strings and not actual HTML. These aren't real elements, at least until the dom is created. This means you cannot dynamically edit these elements unless you select them after they are called then make the change.
Turning a String into an HTML Element
It's a roundabout way but it works!
const stringToHTML = document.createRange().createContextualFragment(thing);
Note, I'm using the
thing
variable from the example before this one as an argument so that it breaks thething
string into html elements.
Now they are in the DOM but not on the page so they can be selected and you can use .appendChild()
or any of the methods we covered before.
Security Pitfalls
If you use innerHTML
on your page and a user has an input that renders to the page - they could put HTML or scripts in the form and take control of your page. I'm going to cover this in my future notes. Stay tuned!
Drew is a seasoned DevOps Engineer with a rich background that spans multiple industries and technologies. With foundational training as a Nuclear Engineer in the US Navy, Drew brings a meticulous approach to operational efficiency and reliability. His expertise lies in cloud migration strategies, CI/CD automation, and Kubernetes orchestration. Known for a keen focus on facts and correctness, Drew is proficient in a range of programming languages including Bash and JavaScript. His diverse experiences, from serving in the military to working in the corporate world, have equipped him with a comprehensive worldview and a knack for creative problem-solving. Drew advocates for streamlined, fact-based approaches in both code and business, making him a reliable authority in the tech industry.