Book of Coding


Change websites dynamically

1. Document Object Model (DOM)

Every time a website is called up in the browser, the browser creates a corresponding model of the website in the working memory, which is referred to as a so-called Document Object Model or DOM for short. The DOM is primarily used to access website content via JavaScript, e.g. to change existing content or add new content. It represents the components of a website hierarchically in a tree representation, which is also referred to as a DOM tree. A DOM tree in turn is made up of so-called nodes, which reflect the structure of a website through their hierarchical arrangement.

For a short introduction to the Document Object Model (DOM) click here:Introduction to the DOM. For more than just an introduction, read on.


2. Select elements


2.1. Select elements by ID

Elements on a website can be assigned an ID via the id attribute. This ID can be used in CSS rules or the corresponding element can be selected via JavaScript using the getElementById() method of the document object. The method only needs to be passed the ID of the element to be selected in the form of a string.

Complete Code - Examples/Part_255/index.js...

 ...
   <style>
     .border {
       border: 3px solid red;
       border-radius: 4px;
       padding: 25px 25px 25px 25px;
       }
   </style>
 </head>
 <body>
 <main id="main">

 </main>
 <script>
   // Selection by ID
   const mainElement = document.getElementById('main');
   mainElement.className = 'border';   
 </script>
 ...
                        


 // Selection by ID
 const mainElement = document.getElementById('main');
 mainElement.className = 'border';
                        

Here, the element with the ID main is selected and saved in the variable mainElement. The class attribute of the element is then changed to the value border via the className property, which results in the element being given a red border with rounded corners.



If no element with the transferred ID can be found, the getElementById() method returns the value null. If an attempt is then made to access a property or method of the supposed element, a runtime error occurs. To prevent this, an if query should be used to ensure that the return value of getElementById() is not null.


 const mainElement = document.getElementById('main');
   if(mainElement !== null) {
     mainElement.className = 'border';
   }
                        

Alternatively, the whole thing can also be shortened with the && operator, where the second operand is only evaluated if the first operand returns a true. So the operand (mainElement.className = 'border') would only be evaluated if mainElement has a value that does not evaluate to false, i.e. is not null.


 const mainElement = document.getElementById('main');
 mainElement && (mainElement.className = 'border');
                        

The check is even shorter with the Optional Chaining Operator ?. The property is only accessed if mainElement is not null or undefined.


  const mainElement = document.getElementById('main');
  mainElement?.className = 'border'; 
                        

2.2. Select elements by class

CSS classes can also be assigned to individual elements on a website, similar to IDs. These classes are managed via the class attribute. An element can have several classes and, unlike IDs, several elements can also have the same class (IDs are unique and may only be assigned once in the code). As a result, the corresponding DOM method getElementsByClassName(), with which a selection by CSS classes is possible, not only returns a single element, but several elements if necessary. The class name is passed to the method as a string as an argument.

Complete Code - Examples/Part_256/...

 ...
 <body>
 <main id="main">
   <h1>List of contacts</h1>
   <table id="contact-list-table" summary="List of contacts">
     <thead>
       <tr>
         <th id="table-header-first-name">First name</th>
         <th id="table-header-last-name">Last name</th>
         <th id="table-header-email ">Email address</th>
       </tr>
     </thead>
     <tbody>
       <tr class="row odd">
         <td>John</td><td>Doe</td><td>john.doe@mail.com</td>
       </tr>
       <tr class="row even">
         <td>Jane</td><td>Doe</td><td>jane.doe@mail.com</td>
       </tr>
       <tr class="row odd">
         <td>Rick</td><td>Sample</td><td>rick.sample@mail.com</td>
       </tr>
       <tr class="row even">
         <td>Morty</td><td>Sample</td><td>morty.sample@mail.com</td>
       </tr>
     </tbody>
   </table>
 </main>
 <script>
     // Selection by class name
     const tableRowsEven = document.getElementsByClassName('even');      // Select all even table rows
       if(tableRowsEven.length > 0) {                                    // If at least one element was found
         for(let i = 0; i < tableRowsEven.length; i++) {                 // Go through all elements
           const tableRow = tableRowsEven[i];                            // Assign element to a variable
           tableRow.style.backgroundColor = '#FADBD8';                   // Set new background color
         }
       }
 </script>
 </body>
 ...
                        


All elements containing the CSS class even are selected here. The return value of getElementsByClassName is a node list (an object of type nodeList), which is to be used similarly to an array. This node list contains the elements in the exact order in which they appear on the web page. Even if node lists look like arrays, they are not arrays. What node lists have in common with arrays is that the individual elements in a node list can be accessed via an index, i.e. the first element can be accessed via tableRowEven[0] the second element via tableRowEven[1] and so on. Another common feature is the length property, which can be used to find out the number of elements in the node list. Here, the for loop is used to iterate over all elements of the list. As with iteration over real arrays, the length property and access by index can be used. In this way, each element in the list is assigned a new background color.

As an alternative to the array syntax with square brackets, the item() method can be used to access individual nodes in a node list.

Complete Code - Examples/Part_256/script.js...

 const tableRowsEven = document.getElementsByClassName('even');      // Select all even table rows
   if(tableRowsEven.length > 0) {                                    // If at least one element was found
     for(let i = 0; i < tableRowsEven.length; i++) {                 // Go through all elements
       const tableRow = tableRowsEven.item(i);                       // Assign element to a variable
       tableRow.style.backgroundColor = '#FADBD8';                   // Set new background color
     }
   }
                        

The index of the element to be returned is also passed as an argument here.

Since node lists are not real arrays, but array-like objects, the method borrowing technique is often used in practice in order to still be able to use methods from arrays:

Complete Code - Examples/Part_256/script.js...

 Array.prototype.forEach.call(tableRowsEven, (tableRow) => {
   tableRow.style.backgroundColor = '#FADBD8';
 });
                        

The selection of an element by ID (getElementById()) is faster in terms of performance compared to other selection methods, as it is not permitted to have several elements with the same ID on a website, and therefore the element can be found quickly. Other selection methods such as getElementsByClassName() are significantly slower in comparison, because every element on the web page has to be checked.


2.3. Select elements by element name

The getElementsByTagName() method can be used to select elements based on their element name. The method expects the name of the element:

Complete Code - Examples/Part_257/...

 ...
 <body>
 <main id="main">
   <h1>List of contacts</h1>
   <table id="contact-list-table" summary="List of contacts">
     <thead>
       <tr>
         <th id="table-header-first-name">First name</th>
         <th id="table-header-last-name">Last name</th>
         <th id="table-header-email ">Email address</th>
       </tr>
     </thead>
     <tbody>
       <tr class="row odd">
         <td>John</td><td>Doe</td><td>john.doe@mail.com</td>
       </tr>
       <tr class="row even">
         <td>Jane</td><td>Doe</td><td>jane.doe@mail.com</td>
       </tr>
       <tr class="row odd">
         <td>Rick</td><td>Sample</td><td>rick.sample@mail.com</td>
       </tr>
       <tr class="row even">
         <td>Morty</td><td>Sample</td><td>morty.sample@mail.com</td>
       </tr>
     </tbody>
   </table>
 </main>
 <script>
  // Selection by element name
  const tableCells = document.getElementsByTagName('td');
    if(tableCells.length > 0) {                         // If at least one element was found
      for(let i = 0; i < tableCells.length; i++) {      // Go through all elements
      const tableCell = tableCells[i];                // Assign element to a variable
      tableCell.style.fontFamily = 'Verdana';         // Set new font
      tableCell.style.fontSize = '12px';              // Set new font size
    }
  };  
 </script>
 </body>
 ...
                        

Here, all table cells are first selected using the getElementsByTagName() method, and then a new font and new font size are assigned to each element. In the getElementsByTagName() method, only the name of the element (here td) is transferred, the angle brackets <> must not be used there.


2.4. Select elements by name

Some elements can be assigned a name attribute in HTML, e.g. <input> elements of type radio, to indicate that they belong to a selection group:

Complete Code - Examples/Part_258/...

 ...
 <body>
 <main id="main">
   <form action="">
     <label for="artist">Artist</label><input id="artist" type="text" name="artist"><br>
     <label for="album">Album</label><input id="album" type="text" name="album"><br>
     <p>Genre:</p>
     <fieldset>
       <input type="radio" id="po" name="genre" value="Pop"><label for="po">Pop</label><br>
       <input type="radio" id="ro" name="genre" value="Rock"><label for="ro">Rock</label><br>
       <input type="radio" id="el" name="genre" value="Electro"><label for="el">Electro</label>
     </fieldset>
   </form>
 </main>
 <script src="script/.js"></script>
 </body>
 ...  
                        

All elements whose name attribute has the value genre are selected here, the name attributes artist and album are not selected.

The values of these elements (inputElement.value) are output in the subsequent loop: Pop, Rock, Electro:

Complete Code - Examples/Part_258/script.js...

 // Selection by name
 const inputElementsForGenre = document.getElementsByName('genre');  // Select all elements with names
   if(inputElementsForGenre.length > 0) {                            // If at least one element was found
     for(let i = 0; i < inputElementsForGenre.length; i++) {         // Go through all elements
       const inputElement = inputElementsForGenre[i];                // Assign element to a variable
       console.log(inputElement.value);                              // output: Pop, Rock, Electro
     }
   }
                        


2.5. Select elements via selector

It is not always the case that the element you want to select has an ID or class, so the methods getElementById() and getElementsByClassName() are of no help in such cases. The method getElementsByTagName() is very unspecific, because usually rather many elements are selected. The method getElementsByName() should be used with caution due to the fact that not all browsers support this method. This is where the querySelector() and querySelectorAll() methods come into play, as they are much more versatile and expressive for returning elements for a given CSS selector.

Complete Code - Examples/Part_259/...

 <body>
 <main id="main">
   <h1>List of contacts</h1>
   <table id="contact-list-table" summary="List of contacts">
     <thead>
       <tr>
         <th id="table-header-first-name">First name</th>
         <th id="table-header-last-name">Last name</th>
         <th id="table-header-email ">Email address</th>
       </tr>
     </thead>
     <tbody>
       <tr class="row odd">
         <td>John</td><td>Doe</td><td>john.doe@mail.com</td>
       </tr>
       <tr class="row even">
         <td>Jane</td><td>Doe</td><td>jane.doe@mail.com</td>
       </tr>
       <tr class="row odd">
         <td>Rick</td><td>Sample</td><td>rick.sample@mail.com</td>
       </tr>
       <tr class="row even">
         <td>Morty</td><td>Sample</td><td>morty.sample@mail.com</td>
       </tr>
     </tbody>
   </table>
 </main>
 <script src="script.js"></script>
 </body>
                        


 // Select elements with querySelector
 const tableCell = document.querySelector('#main table td:nth-child(2)');
 tableCell.style.border = '2px solid red';
                        

The CSS selector #main table td is passed here, which in CSS initially describes the second table cells of each row (td:nth-child(2)) within a table (table) within an element with the ID main (#main). However, as the querySelector() method only selects the first element that matches a selector, only the first <td> element is returned.



The queryySelectorAll() method is used here. The same CSS selector is used here as before. This time, however, it receives all elements that match this selector, i.e. all second <td> elements.

Complete Code - Examples/Part_260/...


 // Select elements with querySelectorAll
 const tableCells = document.querySelectorAll('#main table td:nth-child(2)');
 if(tableCells.length > 0) {
   for(let i=0; i<tableCells.length; i++) {
     const tableCell = tableCells[i];
     tableCell.style.border = '2px solid red';
   }
 }
                        

Within the loop, these elements are then provided with a red frame in the same way as with querySelector().


A short overview of the various selectors in CSS
SelectorDescription
* Selects each element.
[a] Selects elements with the attribute a.
:root Selects the root element of a document.
:nth-child(n) Selects the nth child element of an element.
:nth-last.child(n) Selects the nth child element of an element from behind.
:first-child Selects the first child element of an element.
:last-child Selects the last child element of an element.
:empty Selects elements that have no child elements.
:link Selects links that have not yet been clicked.
:visited Selects links that have already been clicked.
:hover Selects links over which the mouse is currently positioned.
.className Selects elements whose class attribute has the value className
#main Selects elements whose id attribute has the value main.
:not(s) Selects elements that do not match the selector s specified in brackets.
E > F Selects elements of type F that are child elements of an element of type E.

2.6. Select the parent element of an element

Element nodes have various properties that can be used to access related elements. Related elements are parent nodes or parent elements, child nodes or child elements and sibling nodes or sibling elements.

The properties parentNode and parentElement are available for the selection of parent nodes/parent elements, and the properties firstChild, firstElementChild, lastChild, lastElementChild, childNodes and children are available for the selection of child nodes/child elements. The properties previousSibling, previousElementSibling, nextSibling and nextElementSibling are available for the selection of sibling nodes/sibling elements.

To select the parent node of an element (or node), the parentNode property is available, to select the parent element, the parentElement property is available. In most cases, the parent node is also always an element, i.e. the two properties parentNode and parentElement contain the same value:

Complete Code - Examples/Part_261/...

 // Select the parent element of an element
 const table = document.querySelector('table');
 console.log(table.parentNode);      // <main>
 console.log(table.parentElement);   // <main>
                        


Not all nodes in the DOM tree are elements, but all elements are always nodes. It is important to understand that some of the properties mentioned return nodes and other properties return elements. The properties parentNode, childNodes, firstChild, lastChild, previousSibling and nextSibling return nodes. The properties parentElement, children, firstElementChild, lastElementChild, previousElementSibling and nextElementSibling return elements.


 <!DOCTYPE html>
   <!-- parentNode -->
 <html>    <!-- parentElement -> null -->
   <!-- parentNode / parentElement-->
 <body>
   Text  <!-- firstChild (to body) -->
   <!-- nextSibling (text to span) / previousSiblling (span to text) -->
   <span></span>   <!-- firstElementChild to body -->
   <!-- nextSibling / previousSiblling -->
   Text
   <!-- nextSibling / previousSiblling -->
   <span></span>   <!-- lastElementChild (to body) -->
   <!-- nextSibling / previousSiblling -->
   Text  <!-- lastChild to body -->
 </body>
 </html> 
                        

Here is a website with a relatively simple structure, in which there are only two <span> elements within the <body> element and text before and after it.

The corresponding DOM therefore contains a text node, an element node, a text node, an element node and another text node below the <body> element. For all these nodes, the <body> element represents both the parent node and the parent element. This means that the properties parentNode and parentElement have the same value for all these nodes: the <body> element.

The properties parentNode and parentElement generally always reference the same element for all nodes. The only exception is the <html> element. This element does not have a parent element, but only a parent node, i.e. the document node. In this case, the parentElement property returns the value null.


2.7. Select the child elements of an element

The child elements of an element can be determined via the children properties, the child nodes via the childNodes property. Whether an element has child nodes can be determined using the hasChildNodes() method, which returns a Boolean value. Whether an element has child elements can be determined via the childElementCount property, which contains the number of child elements.

Complete Code - Examples/Part_262/index.html...

 ...
  <tbody>
    <tr class="row odd">
      <td>John</td><td>Doe</td><td>john.doe@mail.com</td>
    </tr>
    <tr class="row even">
      <td>Jane</td><td>Doe</td><td>jane.doe@mail.com</td>
    </tr>
    <tr class="row odd">
      <td>Rick</td><td>Sample</td><td>rick.sample@mail.com</td>
    </tr>
    <tr class="row even">
      <td>Morty</td><td>Sample</td><td>morty.sample@mail.com</td>
    </tr>
  </tbody>
 ...
                        

The <tbody> element here has four child elements (<tr>) and a total of nine child nodes. The reason for this is that so-called white space nodes are created even though no text is instanced in the HTML between, before and after the four <tr> elements. These white space nodes are always created when, for example, line breaks are used in HTML between two elements.


Various other properties are available with which individual child elements or child nodes can be selected:

  • firstChild contains the first child node.
  • lastChild contains the last child node.
  • firstElementChild contains the first child element.
  • lastElementChild contains the last child element.

Access to special child nodes and child elements:

Complete Code - Examples/Part_262/...

 const tbody = document.querySelector('tbody');
 console.log(tbody.firstChild);        // Text node
 console.log(tbody.lastChild);         // Text node
 console.log(tbody.firstElementChild); // <tr>
 console.log(tbody.lastElementChild);  // <tr>
                        


2.8. Select the sibling elements of an element

How to select the parent element and the child elements of an element has just been shown. There is also the option of selecting the sibling nodes or sibling elements within a level of the DOM.

  • previousSibling contains the previous sibling node.
  • nextSibling contains the next sibling node.
  • previousElementSibling contains the previous sibling element.
  • nextElementSibling contains the next sibling element.

Access to special sibling nodes and sibling elements:

Complete Code - Examples/Part_262/script.js...

 const tableCell = document.querySelector('tbody tr:nth-child(2)');
 console.log(tableCell.previousSibling);        // Text node
 console.log(tableCell.nextSibling);            // Text node
 console.log(tableCell.previousElementSibling); // <tr>
 console.log(tableCell.nextElementSibling);     // <tr>
                        

Here, starting from the second table row, the preceding (via previousSibling) and the following sibling node (via nextSibling) are selected first; in both cases, this is a text node. The preceding sibling element is then selected via previousElementSibling and the following sibling element via nextElementSibling.


2.9. Call up selection methods on elements

Most DOM methods for selecting elements (getElementsByClassName(), getElementsByTagName(), querySelector(), querySelectorAll()) can be called not only on the document node (document), but also on all other element nodes of a web page (getElementById() and getElementsByName() can only be called on the document node). In this case, the search for the elements includes the subtree below the element on which the respective method was called.

Complete Code - Examples/Part_263/...

<main id="main-content">
  <ul id="list-1">
    <li>List item 1</li>
    <li>
        List item 2
      <ul id="list-2">
        <li>List item 2.1</li>
        <li>List item 2.2</li>
        <li>List item 2.3</li>
        <li>List item 2.4</li>
      </ul>
    </li>
    <li>List item 3</li>
    <li>List item 4</li>
  </ul>
</main>
<script>
  const allListItemElements = document.getElementsByTagName('li');
  console.log(allListItemElements.length);    // output: 8
  const subList = document.getElementById('list-2');
  const subListListItems = subList.getElementsByTagName('li');
  console.log(subListListItems.length);       // output: 4
</script>
                        

Here, the method getElementsByTagName() with the argument li is first called on the document node document, which selects all list entries of the entire web page, and then on the nested list with the ID list-2, which in turn selects only the list entries that occur in this subtree of the DOM, i.e. below the nested list.


2.10. Select elements by type

After the preceding selection methods, the document object offers various properties to directly access certain elements of a web page:


FeatureDescription
document.anchors Contains a list of all anchors of the web page.
document.forms Contains a list of all forms on the website.
document.images Contains a list of all images on the website.
document.links Contains a list of all links on the website.
document.head Access to the <head> element of the web page.
document.body Access to the <body> element of the web page.

3. Work with text nodes

If one or more elements have been selected, they can be changed. Text, attributes and elements can be added or removed. Any text on a web page within the DOM tree is represented as a text node.

The different methods and properties for changing elements:

Property/MethodDescription
textContent This property can be used to access the text content of a node.
nodeValue This property can be used to access the content of a node.
innerHTML This property can be used to access the HTML content of a node.
createTextNode() This method can be used to create text nodes.
createElement() This method can be used to create elements.
createAttribute() Attribute nodes can be created using this method.
appendChild() This method can be used to add nodes to the DOM tree.
removeChild() This method can be used to remove nodes from the DOM tree.

These properties and methods are explained in the following sections.


3.1. Access the text content of an element

To access only the text content of an element, it is best to use the textContent property. The HTML markups within the respective element are ignored, as the textContent property ignores them:

Complete Code - Examples/Part_264/...

 <body>
 <main>
   <ul id="news">
     <li><strong>Daily News: </strong><em>Sasquatch</em> spotted on the moon.</li>
   </ul>
 </main>
 <script>
   const textContent = document.querySelector('#news li:nth-child(1)').textContent;
   console.log(textContent);
   // output: Daily News: Sasquatch spotted on the moon.
 </script>
 </body>  
                        

Here is a simple HTML list with one entry, the text contained there is marked by <strong> and <em> elements. When the textContent property is accessed, only the plain text of the <li> element is output, but not the markups it contains (<strong> and <em>).


3.2. Change the text content of an element

If the text content of an element is to be changed, the textContent property is also used. The new text is simply transferred as the value:

Complete Code - Examples/Part_265/...

  <body>
 <main>
   <ul id="news">
     <li></li>
   </ul>
 </main>
 <script>
   const element = document.querySelector('#news li:nth-child(1)');
   element.textContent = 'Daily News: The moon, Sasquatch was just a rock.';
 </script>
                        

A new text is assigned to the list element here.

However, it should be noted that it is not possible to add markup (HTML markup) via textContent. Although the character string passed contains markup, this is not interpreted but displayed as text.

Complete Code - Examples/Part_266/script.js

 const element = document.querySelector('#news li:nth-child(1)');
 element.textContent = '<strong>Daily News:</strong> The moon, <em>Sasquatch</em> was just a rock';
                        

textContent vs. innerText

In some browsers, the innerText property is still available, which works in a similar way to textContent but is not included in the DOM API and is therefore not supported by Firefox, for example. Therefore, innerText should be avoided.


3.3. Change the HTML below an element

If not only text but also HTML is to be inserted into an element, the innerHTML property can be used. There are other options that are used more frequently in practice, but for simple HTML blocks that are to be added, innerHTML is sufficient.

Complete Code - Examples/Part_267/...

 const element = document.querySelector('#news li:nth-child(1)');
 element.innerHTML = '<strong>Daily News:</strong> The moon, <em>Sasquatch</em> was just a rock.';
                        

In this example, the same HTML block is used as in the previous example, but this time the HTML is also interpreted.

Conversely, the HTML content of an element can also be read via innerHTML. The result is a character string as with textContent, which now contains not only the text content but also the HTML markup:

Complete Code - Examples/Part_268/...

 <body>
   <main>
     <ul id="news">
       <li><strong>Daily News: </strong><em>Sasquatch</em> spotted on the moon.</li>
     </ul>
   </main>
 <script>
   const innerHTML = document.querySelector('#news li:nth-child(1)').innerHTML;
   console.log(innerHTML);
   /* output: <strong>Daily News: </strong><em>Sasquatch</em> spotted on the moon. */
 </script>
 </body>
                        

3.4. Create and add text nodes

As an alternative to textContent and innerHTML, there is also the option of creating text nodes and adding them manually to the DOM tree. This can be done using the createTextNode() method.

Complete Code - Examples/Part_269/...

 <body>
 <main>
   <div id="container">
  
   </div>
 </main>
 <script>
   const element = document.getElementById('container');
   const textNode = document.createTextNode('Hello World');
   element.appendChild(textNode);
 </script>
 </body>
                      

Here, a text node is created using the createTextNode() method and then added to an existing element as a child node using the appendChild() method. This step is necessary because the text is created using the createTextNode() method, but the text node is only added to the DOM tree using appendChild().


4. Work with elements

Elements can also be created manually and can then be added to the domain tree. The createElement() method is used to create elements. This expects the name of the element to be created as a parameter and returns the new element. The new element is not yet added to the DOM when the method is called.


4.1. Create and add elements

There are various options for adding generated elements to the DOM:

  • Using insertBefore(), the element can be added as a child element before another element/node, i.e. defined as a previous sibling element.
  • Via appendChild() the element can be added as the last child element of a parent element.
  • An existing child element can be replaced with a new child element using replaceChild(). The method is called on the parent element and expects the new child node as the first parameter and the child node to be replaced as the second parameter.

Complete Code - Examples/Part_270/...

 <body onload="createTable()">
 <main id="main-content">
   <h1>List of contacts</h1>
   <table id="contact-table" summary="List of contacts">
     <thead>
       <tr>
         <th>First name</th>
         <th>Last name</th>
         <th>Email address</th>
       </tr>
     </thead>
     <tbody>
     </tbody>
   </table>
 </main>
 <script>
 const contacts = [
     {
       firstName: 'John ',
       lastName: 'Doe',
       email: 'john.doe@mail.com'
     },
     {
       firstName: 'Jane',
       lastName: 'Doe',
       email: 'jane.doe@mail.com'
     },
     {
       firstName: 'Rick ',
       lastName: 'Sample',
       email: 'rick.sample@mail.com'
     }
   ];

   function createTable() {
     const tableBody = document.querySelector('#contact-table tbody');
     for(let i=0; i<contacts.length; i++) {
       // For the current contact ...
       const contact = contacts[i];
       // ... a new line is created.
       // (1)
       const tableRow = document.createElement('tr');
       // Various cells are created within the row ...
       // (2)
       const tableCellFirstName = document.createElement('td');
       // ... and each filled with values.
       // (3)
       const firstName = document.createTextNode(contact.firstName);
       // (4)
       tableCellFirstName.appendChild(firstName);
       // (5)
       const tableCellLastName = document.createElement('td');
       // (6)
       const lastName = document.createTextNode(contact.lastName);
       // (7)
       tableCellLastName.appendChild(lastName);
       // (8)
       const tableCellEmail = document.createElement('td');
       // (9)
       const email = document.createTextNode(contact.email);
       // (10)
       tableCellEmail.appendChild(email);
       // (11)
       tableRow.appendChild(tableCellFirstName);
       // (12)
       tableRow.appendChild(tableCellLastName);
       // (13)
       tableRow.appendChild(tableCellEmail);
       // (14)
       tableBody.appendChild(tableRow);
     }
   }

 </script>
 </body>
								      

An HTML table is generated here based on a contact list. The individual entries in the contact list contain information on the name and email address of the respective contact. The corresponding elements are created within the createElement() function. First, the <tbody> element in the HTML table is selected using the querySelector() method and then iterated over the array with the contact information. A table row <tr> is created for each entry using the createElement() method and a table row <td> is created for each property (firstName, lastName, email). Using the createTextNode() method, corresponding text nodes are created for the values of the properties and added to the respective <td> element using appendChild(). The generated table cells are then added to the corresponding table row as child elements at the end of the iteration and, in the last row of the iteration, the table row is added as a child element of the table body <tbody>.


4.2. Remove elements and nodes

To remove elements from a parent element, the removeChild() method is available. This method expects the element to be removed and also returns this as the return value.

Complete Code - Examples/Part_271/...

 ...
  function sortByFirstName() {
    const tableBody = document.querySelector('#contact-table tbody');
    while (tableBody.firstChild !== null) {
      tableBody.removeChild(tableBody.firstChild);
    }
    contacts.sort(function(contact1, contact2) {
      return contact1.firstName.localeCompare(contact2.firstName);
    })
    createTable();
  }   
 ...
								      

A method for filtering table data (sortByFirstName()) was created here, in which the removeChild() method is used to remove all child nodes and child elements from the table body so that they can then be sorted.


5. Work with attributes

Various methods are available in the DOM API for working with attributes:

  • The getAttribute() method can be used to access the attributes of an element set.
  • The setAttribute() method can be used to change the value of an attribute or add an attribute to an element.
  • Attribute accounts can be created via the createAttribute() method and added to these via setAttributeNode().
  • Attributes can be removed using the removeAttribute() method.

5.1. Read out the value of an attribute

To access the value of an attribute, the getAttribute() method is used. The method expects the name of the respective HTML attribute as a parameter. The value of the corresponding attribute is output as the return value:

Complete Code - Examples/Part_272/...

 <body>
   <a id="home" class="link" href="index.html">Home</a>
   <button id="create" class="link" style="background-color: white" onclick="createContact()">Create contact</button>
   <script>
     const element = document.getElementById('home');
     console.log(element.getAttribute('id'));        // home
     console.log(element.getAttribute('class'));     // link
     console.log(element.getAttribute('href'));      // index.html
   </script>
 </body> 
								      

Attributes of an element are usually also available as properties with the same name, however the attribute “class” is an exception. This attribute can be accessed via the className property.


 console.log(element.id);           // home
 console.log(element.className);    // link
 console.log(element.href);         // index.html
								      

The attributes id and href can be read via the properties of the same name, the attribute class via the property className.

It should be noted, however, that with two attributes, access via the getAttribute() method returns a different return value than direct access via the property. For the style attribute, the getAttribute() method only returns the text that the attribute contains as a value. Access via the style property, on the other hand, returns an object of the type CSSStyleDeclaration, which can be used to access the corresponding CSS information in detail. In addition, all attributes that are used to define event handlers return the JavaScript code to be executed as a function object via the corresponding property (e.g. onclick). However, if you access the respective attribute via the getAttribute() method, the name of the function to be executed is returned as text.

Complete Code - Examples/Part_273/...

 <body>
   <a id="home" class="link" href="index.html">Home</a>
   <button id="create" class="link" style="background-color: white" onclick="createContact()">Create contact</button>
   <script>
     const button = document.getElementById('create');
     console.log(button.onclick);                        // Output of the function
     console.log(typeof button.onclick);                 // Output: function
     console.log(button.getAttribute('onclick'));        // createContact()
     console.log(typeof button.getAttribute('onclick')); // Output: string
     console.log(button.style);                          // Output of the CSSStyleDeclaration
     console.log(typeof button.style);                   // Output: object
     console.log(button.getAttribute('style'));          // background-color: white
     console.log(typeof button.getAttribute('style'));   // Output: string
   </script>
 </body>
								      

Here is an HTML button with various attributes, including a style attribute and an onclick attribute. The reason why direct access to event handler attributes such as onclick does not return a character string but a function is that you can use this property to define event handlers for the respective element. In other words, you can assign function objects to this property. The reason why direct access to the style attribute does not return a character string is that the CSS information of the respective element can be accessed via this attribute.


5.2. Change the value of an attribute or add a new attribute

To change the value of an attribute or add a new attribute, the setAttribute() method is used on the element. This expects two parameters, the name of the attribute and the new value. If the element already has an attribute with the same name, the value is overwritten with the new value. However, if the attribute does not yet exist, a new one is added to the element.

Complete Code - Examples/Part_274/...

 <body>
   <a id="home" class="link" href="index.html">Home</a>
   <script>
     const element = document.getElementById('home');
     element.setAttribute('class', 'link active');
     element.setAttribute('href', 'newlink.html');
     element.setAttribute('target', '_blank');
     console.log(element.getAttribute('class'));   // link active
     console.log(element.getAttribute('href'));    // newlink.html
     console.log(element.getAttribute('target'));  // _blank
   </script>
 </body>
								      

Here, the properties class, href and target are changed for the previously selected link element.

Alternatively, the values of attributes can also be changed or new ones added via the object properties of the same name:

Complete Code - Examples/Part_274/...

 <body>
   <a id="home" class="link" href="index.html">Home</a>
   <script>
     const element = document.getElementById('home');
     element.className = 'link active highlighted';
     element.href = 'anotherLink.html';
     element.target = '_self';
     console.log(element.getAttribute('class'));   // link active highlighted
     console.log(element.getAttribute('href'));    // anotherLink.html
     console.log(element.getAttribute('target'));  // _self
   </script>
 </body>
								      

When the setAttribute() method is used, an attribute node is created in the background and added to the DOM tree at the corresponding element node as a child node.


5.3. Create and add attribute nodes

Attributes can also be created as attribute nodes using a special method, the createAttribute() method. This method expects the name of the attribute to be created as an argument and returns the new attribute node as the return value. However, this is not yet built directly into the DOM tree. This must be done manually using the setAttributeNode() method on the corresponding element.

Complete Code - Examples/Part_275/...

 <body>
   <a id="home" class="link" href="index.html">Home</a>
   <script>
     const element = document.getElementById('home');
     const attribute = document.createAttribute('target');
     attribute.value = '_blank';
     element.setAttributeNode(attribute);
     console.log(element.getAttribute('target'));  // _blank
   </script>
 </body>
								      


5.4. Remove attributes

The attributes can be removed from an element again using the removeAttribute() method.

Complete Code - Examples/Part_276/...

 <body>
   <a id="home" class="link" href="index.html">Home</a>
   <script>
     const element = document.getElementById('home');
     element.removeAttribute('class');
     element.removeAttribute('href');
     console.log(element.getAttribute('class'));   // null
     console.log(element.getAttribute('href'));    // null
   </script>
 </body>
								      

Here, the two attributes class and href are removed from the link element with removeAttribute().



5.5. Access CSS classes

First of all, there is the className property, which every element on a website has. This property simply contains the value of the class attribute of the corresponding element as a string separated by spaces. Since version 4 of the DOM API, elements also have the classList property, which contains the CSS classes as a list:

  • New CSS classes can be added to the list using the add() method.
  • CSS classes can be removed from the list using the remove() method.
  • The toggle() method can be used to toggle CSS classes, i.e. if the class exists in the list, it is deleted, but if it does not exist, it is added.
  • The contains() method can also be used to check whether a CSS class is contained in the list.
Complete Code - Examples/Part_277/...

 <body>
   <a id="home" class="link" href="index.html">Home</a>
   <script>
     const element = document.getElementById('home');
     console.log(element.classList);                     // ["link"]
     element.classList.add('active');                    // Add class
     console.log(element.classList);                     // ["link", "active"]
     element.classList.remove('active');                 // Remove class
     console.log(element.classList);                     // ["link"]
     element.classList.toggle('active');                 // Toggle class
     console.log(element.classList);                     // ["link", "active"]
     element.classList.toggle('active');                 // Toggle class
     console.log(element.classList);                     // ["link"]
     console.log(element.classList.contains('link'));    // true
     console.log(element.classList.contains('active'));  // false
     let i = 5;
     const condition = i > 0;
     element.classList.toggle('active', condition);      // Toggle class
     console.log(element.classList);                     // ["link", "active"]
   </script>
 </body>
								      


Related links: