DOM: creating elements

Post Statistics

This post has 4360 words.
This post has 27475 characters.
This post reading time is approximately 19 minute(s)

Manipulating the DOM: creating elements

In this course, we are going to see what it means to "create elements" on the web page, thereby directly manipulating the DOM using the document.createElement() method.

Manipulating the DOM: document.createElement()

Creates an HTML element on the page specified by tagName, or an HTMLUnknownElement if tagName is not recognized. Make it a habit, however, of creating recognized elements only!

Syntax:

const element = document.createElement(nodeName);

Parameters:

nodeName (type String): Required. The name of the element you want to create.

Return value: a new Element.

Code Example:

function createNode(element) {
    return document.createElement(element);
}

The above code is a helper function taken from the Monsters API App.

You may have noticed that there are no quotes around the element argument passed in to document.createElement(). There ARE quotes around the value of element when the createNode() function is called:

let li = createNode('li');

You can also remove elements from the DOM with the .remove() method.

To learn more, please visit ChildNode.remove() on MDN.

Manipulating the DOM: Element.setAttribute()

Definition:

his method sets the value of an attribute on the specified element. If the attribute already exists, the value is updatedOtherwise, a new attribute is added with the specified name and value.

Syntax:

Element.setAttribute(name, value);

Parameters:

name: A DOMStringspecifying the name of the attribute whose value is to be set. The attribute name is automaticallyconverted to all lower-case when setAttribute() is called on an HTML elementresiding in an HTML document.

value: A DOMStringcontaining the value to assign to the attribute. Any non-stringvaluespecified is automatically converted into a string.

Return valueundefined.

Exceptions:

InvalidCharacterError: The specifiedattribute namecontains one or more characters which are notvalid in attribute names.

You can also get attributes with the .getAttribute() method and remove attributes with the .removeAttribute() method.

To learn more, please refer to the Related Resources slide at the end of this post.

Code Example:

img.setAttribute('src', `${imageUrl}`);

This is a good example of how the value of the src attribute can be dynamic too.

Manipulating the DOM: Node.appendChild()

Node.appendChild() is a method of the Node interface.

The Node.appendChild() method adds a node to the end of the list of children of a specified parent node. If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position.

This means that a node can’t be in two points of the document simultaneously. So if the node already has a parent, the node is first removed, then appended at the new position.

Syntax:

element.appendChild(aChild)

Parameters:

aChild:

The node to append to the given parent node (commonly an element).

Return value:

The returned value is the appended child (aChild).

Code Example:

document.body.appendChild(downloadLink.download);

Code Example:

function append(parent, el) {
    parent.appendChild(el);
}

This code is taken from our Monsters Search API Project 8 application associated with this course.

In essence, the createElement() and appendChild() methods contribute to the extension of the DOM Tree.

Manipulating the DOM: the Node Interface

What is the Node interface? It is an interface that is implemented by a large number of objectsincluding document, and element, for example.

node, then, in the context of the DOMmeans any object that implements the Node interfaceUsually it is an element object representing an HTML element.

Manipulating the DOM: HTML parsing

In the slide deck An Introduction to JavaScript and the DOM, I discuss the HTML Parser, which is implemented by the browser, and is responsible for the encodingpre-parsingtokenization, and tree formation of the DOM.

The WHATWG (Web Hypertext Application Technology Working Groupbest describes this process in their HTML Living Standard:

Overview of the parsing model: a stream of code points is input into the HTML parsing process, and passed through a tokenization stage, followed by a tree construction stage. The output is a Document object.

Manipulating The DOM: tokenization

In Introduction to JavaScript and the DOM, I discuss tokenization.

Tokenization refers to the process by which a stream of code points are transformed from HTML markup (what you create in the Code Editor) into individual tokens such as a “begin tag”“opening tag”“end tag”, etc.

Manipulating The DOM: tokenization

Manipulating the DOM: code points

code point: refers to the numbers assigned to characters that are needed for a specific purpose (i.e., HTML text), and are grouped into a specific character set (also called a repertoire). You may also know character set as "charset". The associated html tag is called meta charset. The character set used in html pages is "utf-8".

To display an HTML page correctly, a web browser must know which character set to use. That’s why the meta charset tag is so important.

The default character set for HTML5 is UTF-8.

UTF-8 (Unicode) covers almost all of the characters and symbols in the world.

In essencewords and sentences in text are created from such characters associated with specific code pointsGenerally, however, the default these days is UTF-8.

To learn more, please refer to the Related Resources slide at the end of this slide deck.

Manipulating The DOM: construction of the DOM Tree

When a token is produced, it must immediately be handled by the tree construction stage.

The input to the tree construction stage is a sequence of tokens from the tokenization stage.

The tree construction stage is associated with a DOM Document object when a parser is created.

The output of this stage consists of dynamically modifying or extending that Document’s DOM Tree.

In essence, the DOM represents HTML as a tree structure of tags.

Manipulating The DOM: construction of the DOM Tree

Manipulating the DOM: Document.createTextNode()

All viewable HTML text in a web page (except text in form elements or custom embedded objects) is in text nodes.

Web pages consist of a number of different types of nodesSome have child nodes and some don’t. To learn more about the different node types, please visit Node.nodeType on MDN.

Manipulating the DOM: document.createTextNode() breakdown

Definition:

Creates a Text Node with the specified textHTML elements often consist of both an element node and a text node. Let’s say you want to create a header element that contained text. You would have to create both an h1 element and a text node.

Syntax:

document.createTextNode(text);

Parameters:

text (required): of type String. It is the text of the Text Node.

Return value: A Text Node object with the created Text Node.

As we went over earlier, first we would use the .createElement() method to create an Element Node using the specified element name.

After creating the Element Node, we would create a Text Node with the specified text for the Element Node. In this case, we would create a Text Node for the h1 Element Node we just created using document.createTextNode().

Finally, after creating the text node for the h1 Element Node, we would use the Element.appendChild() method (or the Element.insertBefore() method) to append the Node Element to a Parent Element.

Example Code:

const para = document.createElement("p");
const paraTextNode = document.createTextNode(`I was working in the lab, late one night
When my eyes beheld an eerie sight
For my monster from his slab, began to rise
And suddenly to my surprise...`);
para.appendChild(paraTextNode);
document.body.appendChild(para);

In more modern browsers, you could achieve the same using either the .innerHTML property or the .textContent property.

Manipulating the DOM: textNode vs innerHTML

When you set the .innerHTML property of an Element Node, i.e., li, it creates the appropriate nodes and makes them child nodes of the element that you set the .innerHTML property on. If there is text in the .innerHTML you set, then text nodes will be created to hold that text.

Code Example:

const wrapperContainer = document.querySelector(".wrapper-container");
const newSection = document.createElement("section");
// append newSection to wrapperContainer
wrapperContainer.appendChild(newSection);
// create p tag
const newPara = document.createElement("p");
newSection.appendChild(newPara);
const newContent = document.createTextNode(
"I just created my first HTML elements!"
);
newPara.appendChild(newContent);

Manipulating the DOM: when textNode is preferable over innerHTML

Usually one would not want to manipulate text nodes directly using createTextNode(), i.e., since the same can be achieved using .innerHTML.

On the other hand, you may want to display some text without the security risks that it might contain other markup that the browser would parse and interpret if you used .innerHTML.

So, you create a Text Node and set the value of its text, and the browser won’t interpret any HTML in it.

Modern browsers can also use the .textContent property to solve the same problem as well.

To learn more, please visit What Is A Text Node, Its Uses? //document.createTextNode() on stackoverflow.

Manipulating The DOM: .textContent vs .innerHTML

We’ve already seen .innerHTML in action, and we have seen and used examples of .textContent along the way. They basically do the same thing – replace what is between the opening and closing tag of an element.

.textContent only does that with text content.

On the other hand, .innerHTML takes both text and markup into consideration.

Manipulating the DOM in action

function addElement() {
    document.body.setAttribute("class", "Site");
    document.body.setAttribute("id", "Site");
    // create the outer container element
    const outerContainer = document.createElement("div");
    outerContainer.setAttribute("class", "Site-content");
    document.body.appendChild(outerContainer);
    // create wrapper container that contains all the other elements
    // all tags bound in the same way to wrapperContainer either directly
    // or through parent.
    const wrapperContainer = document.createElement("div");
    // append wrapperContainer to body
    document.body.appendChild(wrapperContainer);
    // create wrapperContainer class
    wrapperContainer.classList.add("wrapper-container");
    // create app title
    const manipulateDOM = document.createElement("h1");
    // set id attribute
    manipulateDOM.setAttribute("id", "manipulate-dom");
    // set manipulateDOM innerHTML
    manipulateDOM.innerHTML = `Welcome to my DOM manipulation site!`;
    // append manipulateDOM to wrapperContainer
    wrapperContainer.appendChild(manipulateDOM);
    // create new section element
    const newSection = document.createElement("section");
    // append newSection to wrapperContainer
    wrapperContainer.appendChild(newSection);
    // create p tag
    const newPara = document.createElement("p");
    newSection.appendChild(newPara);
    const newContent = document.createTextNode(
    "I just created my first HTML elements!"
    );
    newPara.appendChild(newContent);
    // add new elements and their content to the DOM
    const bodySection = document.getElementById("Site");
}
document.body.onload = addElement;

Manipulating the DOM: recap

In the previous slide, we created some new elements and manipulated the DOM with the following methods:

document.createElement('tagName')

document.setAttribute('attrName', 'value')

document.appendChild(childIdentifierName)

document.createTextNode('Some text')

document.body.onload

Removing/Adding Attributes revisited

Live example of removing/adding attributes can be found here on the slide deck related to the subject of this course hosted on Github gh-pages: Removing/Adding Attributes.

Removing/Adding Attributes: code

JavaScript:

function toggleSrc() {
    let image = document.getElementById('image');
    const hiddenCan = 'Hidden_Can.png';
    const visibleCan = 'Visible_Can.png';
    if (image.getAttribute('src') === hiddenCan) {
        image.setAttribute("src", visibleCan);
    } else {
        image.setAttribute("src", hiddenCan);
    }
}
const imgBtn = document.getElementById('imageBtn');
imgBtn.addEventListener('click', toggleSrc);

HTML:

<div id="wrapper">
    <img src="Hidden_Can.png" id="image">
    <button type="button" id="imageBtn">change me!</button>
</div>

Creating elements and the load event

Did you ever notice how sometimes a web page takes such a long time to load, or the page seems to have to be refreshed a number of times before any of the content comes into view?

This is especially the case when there is a lot of styling involved, images to load, and even APIs to fetch, which might be populating your images as well as data content within your document.

The reason why I bring this up in this particular slide deck, is because in Project 8, the Monsters API App, is all about creating elements. The only thing we already have in index.html inside of the body tag is a ul tag. Everything else is created with the built-in method createElement()set on the document object.

So what does creating elements have to do with the load event? What if a page is loaded and the elements which are being created with the createElement() method haven’t been created yet? Nothing would render to the page!

Creating elements and the load event: scripts & external stylesheets

If a script tag comes after an external stylesheet, then that script must wait until the stylesheet loads.

The reason why this happens is because the script may want to get style dependent properties of elements.

Example:

const monstersBtn = document.querySelector('.monsters-btn');
 monstersBtn.addEventListener('click', fetchMonsters);

The most common workaround for this is to place the script at the bottom of the index.htmlright before the closing body tag. However, that does not completely take care of the issue. What if the page is very long and/or has many elements to load? In cases like that, the browser may pick up on the script tag but start downloading it only after it has downloaded the whole HTML document. For long HTML documents, this may result in a long delay.

Creating elements and the load event: page load performance

When loading a script on an HTML page, you need to be careful not to damage the page’s load performance.

<script src="main.js"></script>

Whenever the HTML parser comes across the script tag, a request is made to fetch the script, and the script is executed.

Once the process is complete, the parsing can continue, and the rest of the HTML analyzed.

If the script takes longer to load than expected, the visitor will probably see a blank page until the script is completely executed.

Creating elements and the load event: the importance of the script position

When some of us first started learning HTML, we may have been told to place the script tag in the head. Giving the parser immediate access to the script tag could result in even longer page load delays. It’s only after the tag has been executed will the parser continue parsing the rest of the HTML.

The common solution to this problem is to place the script tag at the bottom of the pageright above the closing body tag.

This is definitely a great improvement, as the script is then loaded and executed after the page is already parsed and loaded.

This is the best way to go if you need to support older browsers that do not support the relatively recent async and defer attributes.

Creating elements and the load event: async and defer script attributes

Both async and defer are boolean attributes. They are added to the script tag in the same way:

<script async="" src="main.js"></script>
<script defer="" src="main.js"></script>

Please note that in actualityasync, and defer, as shown in the slide deck markup itself, does not have an explicitly visible value. It either is true or false. Please ignore the ="".

If one includes both in a script tagasync takes precedence in modern browsers, and defer takes precedence in older browsers.

Using either of these attributes only makes sense if you are placing the script tag in the head. They don’t do anything if you place your script tag above the closing body tag.

Creating elements and the load event: the async vs defer script tag attribute

No defer or async attribute in the script tag right above the closing body tag:

The parsing takes place without interruption, and only when it is finished is the script loaded and executed. This means that the page is viewable by the user way before it would have been if the script tag had been placed in the head.

async script attribute in the head:

The script is fetched asynchronously, and when the script is ready for execution, the HTML parsing is paused, allowing for execution of the script, and afterwards, the HTML parsing is continued.

defer script attribute in the head:

The script is fetched asynchronously, and it’s executed only after the HTML parsing is doneParsing is completed the same way as with the script tag right above the closing body tag, but the process is much faster, because the script has been downloaded in parallel with the HTML parsing. This is the best way to go, and what I ended up doing in the Monsters API App.

async blocks parsing:

async blocks parsing of the pagedefer does not.

blocking rendering:

Neither async nor defer guarantee that rendering will not be blocked. It is up to you to make sure that it is not. i.e., making sure that your scripts run after the load event.

keeping scripts in order:

async ignores the order of scriptsscripts with the async attribute are executed as they become available. This can be a problem when order matters. And oftentimes, it doesscripts with the defer attribute are executed after parsing has been completed, and in the order in which they are defined in the markup.

To learn more about async vs defer, please visit the post entitled Efficiently load JavaScript with defer and async by Flavio Copes.

Related Resources

Document.createElement()MDN
HTMLElementMDN
HTMLUnknownElementMDN
JavaScript: How can I check for “HTMLUnknownElement”? stackoverflow
HTML DOM createElement() MethodW3Schools
Element.setAttribute()MDN
JavaScript appendChildJavaScript Tutorial
Modifying the documentJavaScript.info
What Is A Text Node, Its Uses? //document.createTextNode()stackoverflow
HTML DOM createTextNode() MethodW3Schools
JavaScript onloadJavaScript Tutorial
Script Tag – async & deferstackoverflow
Difference between document.addEventListener and window.addEventListener?stackoverflow
Page: DOMContentLoaded, load, beforeunload, unloadjavascript.info
Scripts: async, deferjavascript.info
Efficiently load JavaScript with defer and asyncFlavio Copes
What is a node in Javascript?stackoverflow
An Intro To JavaScript And The DOMinterglobalmedia Github gh-pages
NodeMDN
12.2.1 Overview of the parsing modelHTML: The Living Standard (Web Hypertext Application Technology Working Group)
Character encodings for beginnersW3C
HTML Encoding (Character Sets)W3Schools
DOM treejavascript.info
DOM Tree constructionWHATWG