Lesson 10 JavaScript Manipulating the DOM

Mark Harder, 30 November 2018

JavaScript and the DOM

Access to the DOM

Different browsers have different implementations of the DOM, and these implementations exhibit varying degrees of conformance to the actual DOM standard, but every web browser uses some document object model to make web pages accessible via JavaScript. The current evergreen browsers are good at implementing the basics.

Evergreen browser is a term used for browsers like Google Chrome, Mozilla Firefox, Microsoft Edge and Apple Safari, which update regularly in the background. This is useful for programmers of the web, after a new feature has appeared in all the evergreen browsers, then it can be used. Historically web developers needed to support old browser’s that didn’t update in their frozen state for years.

Common DOM APIs with examples

HTML for our examples index.html

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

<body>  
    <h1 id="ListTitle">Mark's List of Top 10 Board Games</h1>  
    <article>  
        <ol class="TopTen"></ol>  
    </article>  
</body>  
  • the defer attribute on the script tag delays the running of the script till the HTML page is loaded.
  • We have an id on our header so that we can change the text content in our JavaScript code.
  • Our ol element (ordered list) lacks li (list items), because we are going to add our list items using JavaScript code.

Starting JavaScript page for our examples:> main.js

// Here is our array of board games  
let boardGames = ['Catan', 'Pandemic', 'Ticket to Ride', 'Harbour', 'King of Tokyo', 'Forbidden Island', 'Dragonwood', 'Lost Cities'];  
  
// Update the title with the total number of games from our array length  
document.querySelector('h1').textContent = "Mark's List of Top " + boardGames.length + " Board Games"  
  • Lets break down the last line of code, which changes the text for the h1 element.

    .document.querySelector(‘h1’)

    • We use a CSS selector like we have done before to find the first h1 element in our HTML page DOM

      .textContent = “”

    • We are going to assign a new string to the property “textContent” of our element.

      = “Mark’s List of Top “ + boardGames.length + “ Board Games”

    • Create a new string with the number of items in the boardGames array using the .length property that all arrays have.

Selecting the first h1 element is not precise, so lets change our code to select the h1 element based on its unique id attribute. ListTitle

document.querySelector(‘#ListTitle’).textContent = “Mark’s List of Top “ + boardGames.length + “ Board Games”

Single Element Selectors

  • document.querySelector();

    Parameter: CSS selector string
    Returns: the first element found that matches the selector.

  • document.getElementById();

    Parameter: id string of an element in the DOM.
    Returns: documentElement

    Lets try the line of code where we change the h1 text again, using getElementById

    document.getElementById(‘ListTitle’).textContent = “Top “ + boardGames.length + “ Board Games”

Multiple Element Selectors

  • document.getElementByClassName();

    Parameter: class string of element class names.
    Returns: an array of elements from the DOM with the matching class names.

    • the getElementByClassName() method can also be called on an element in the DOM, in which case it will use the element as the root of the search.

      The returned array can contain zero items if none are found, so it is a good idea to check the length of the returned array.

  • document.querySelectorAll();

    Parameter: CSS selector string
    Returns: an array of elements that matches the selector.

Creating a new element to add to the DOM

  • Create a new element

    let newLi = document.createElement(tagName);

    • tagName: a string specifying the element. e.g. h1, article, p, img, a, li
    • Return value: the new HTML Element
    • Note: this new element still doesn’t have a location in your DOM
  • Add content (text between the element tags)

    let elementContent = document.createTextNode(“List of Top Board Games”);
    newLi.appendChild(elementContent);

    • first we create a Text node with our text by calling the method createTextNode()
    • then we attach it to the new element using the method .appendChild()
  • Place the new element into the DOM, then it will appear on our page.
    • Then we attach the new li element as a child of the element ol (order list)

      let listParent = document.querySelector(‘.TopTen’);
      listParent.appendChild(newLi);

  • Lets try this out in our code for the first game in our array.
      // main.js: This code starts to run after the HTML page is loaded, because of defer attribute in script tag.  
      let boardGames = ['Catan', 'Pandemic', 'Ticket to Ride', 'Harbour', 'King of Tokyo', 'Forbidden Island', 'Dragonwood', 'Lost Cities'];  
        
      // Update the title with the total number of games from our array length  
      document.getElementById('ListTitle').textContent = "Top " + boardGames.length + " Board Games"  
        
      // Retrieve the ordered list element (ol) so we can add list items (li)
      let listParent = document.querySelector('.TopTen');  
          
      let newLi = document.createElement("li");  
      let itemText = document.createTextNode('Catan');  
      newLi.appendChild(itemText);  
      listParent.appendChild(newLi);   
    

  • Video Link for loop adding list items
    • Length: 7:38 minutes
    • Size: 32.4 MB

Use a For loop to add all the games in the array.

Previously we learned about using a for loop with a syntax of:

for (let count = 0; count < boardGames.length; count++) { };

  • we can use the variable count, which is a number starting at 0 going to length -1, to access each array row.
  • boardGame[count] will allow us access to each array row item.
  • replace the bottom three lines with this for loop.
    for (let count = 0; count < boardGames.length; count++) {  
      let newLi = document.createElement("li");  
      let itemText = document.createTextNode(boardGames[count]);  
      newLi.appendChild(itemText);  
      console.log(newLi);  
      listParent.appendChild(newLi);  
    };  
    
  • Look in the console and you will see the console.log listing the array li elements
  • You should now have a list of all the games in your array displayed on your page.

  • Video Link Show how to use a forEach loop array method
    • Length: 4:36 minutes
    • Size: 23.2 MB
      Code created in video:
      boardGames.forEach((game) => {
        let li = document.createElement("li");
        li.appendChild(document.createTextNode(game));
        console.log(li);
        listParent.appendChild(li); 
      });  
      

Change a style on an Element in JavaScript

We can apply CCS like changes to elements using the DOM in JavaScript.

  • Let’s add a new line of JavaScript at the bottom of our file. Because JavaScript is code that runs sequentially, each of the lines will add will run in order.

    document.querySelector(‘li’).style.color = ‘red’;
    Using the DOM this runs a CSS querySelector to grab the first li item, which is not in our HTML page, but was added in our for loop.

    The query selector returns the li element, so we can now add a . to work on items in the element object. We are going to apply a change to the style object’s property called color, setting it to red.

    This is like a CSS statement:

      li:nth-child(1) {
          color: red;
      }
    

    In our example CSS the :nth-child(#) is used here in this example to select the first item, like the querySelector method is selecting only one. We can use the nth-child selector in the JavaScript to select the nth li element.

  • In CSS it is easy to apply a change to a group of items using a selector like this:
      li {
          color: red;
      }
    

    All List Items will be turned red. In JavaScript this is more difficult because we now have to work with each item one at a time.

    document.querySelectorAll(‘li’).forEach((el) => el.style.color = ‘red’ );

    Lets break this down.

    document.querySelectorAll(‘li’)

    • this returns an array of li element objects.
      .forEach();
    • this operated on each of the items in the array. So we need to put our function (block of code) which will run for each object in the array.
      (el) => el.style.color = ‘red’
    • this is our function. This function can also be written this way:
        function (el) {  
        el.style.color = 'red';  
        }  
      
    • so here is what the code would look like in its longer form.
        document.querySelectorAll('li').forEach( 
        function(el) {
            el.style.color = 'red'
        }
        );
      
    • I personally like the shorter form () => {} this is called an arrow function.

Change the text content of an element in JavaScript

We have seen JavaScript select elements, add elements, and even change the style of elements, last lets change the text of an element.

  • Let’s start by changing the first item’s text.

    document.querySelector(‘li:nth-child(1)’).textContent = ‘Monopoly’;

    • using querySelector we selected the first item. then we changed it’s text from saying ‘Catan’ to ‘Monopoly’.
  • Let’s change the code we made to add li to the page, and add a class-name of ‘Game-Item’ to each list item before showing it on the screen.
      boardGames.forEach((game) => {
          let li = document.createElement("li");
          li.appendChild(document.createTextNode(game));
          console.log(li);
          li.className = 'Game-Item';
          listParent.appendChild(li); 
      });  
    

  • Video Link Find and Replace one list item for another
    • Length: 6:46 minutes
    • Size: 37.9 MB
  • After adding a className to each list item, we can use the DOM method .getElementsByClassName to retrieve an array of list items for us to work with.
  • Now we can use a for loop to search for the item with a game of ‘Harbour’ and change its name to Monopoly.
      const items = document.getElementsByClassName('Game-Item');  
      for (let count =0; count < items.length; count++) {  
          console.log(items[count]);  
          if (items[count].textContent === 'Harbour') {  
              items[count].textContent = 'Monopoly';  
          }  
      }  
    
    • This code does a loop through each item in the list of li elements.
    • Then we compare the string from txtContext and our target ‘Harbour’ using ===
    • We set the items[count].textContent to be our new ‘Monopoly’

Assignment due for discussion next class and checked into GitHub by the Monday after that.

  • create a new repo called lesson10
  • Use the result of this lesson as a starting point for your assignment.
  • Now add or modify the JavaScript code to reverse the order so that the last items in the array is #1 in the list.
  • You can download the code from the lesson at https://github.com/mhintegrity/lesson10