Play with DOM

Reading time ~6 minutes

The Document Object Model

The DOM, in short, is an in-memory object representing an HTML document. There is a good introduction in MDN.

What is DOM nodes

dom tree

You can view a HTML tags as a nodes. But actually, it has different names on it:

  • Element represents HTML tags.
  • Text nodes represents text or white space
  • Comments represents HTML comments.

So HTML is an element, head, body is an element nodes, too.

Understand Node Properties

first, We use document to represents entire HTML document. Everything is from here. It is an HTMLDocument element inheriting from Node

properties which node? return what? explain
nodeName Element uppercase, HTML tags text node is #text
nodeType nodes 1 is element, 3 is text MDN
nodeValue Text   Element nodes don’t have a value
textContent Element   all child nodes concatenated into a single String

Types of Node

  • All objects in DOM are Nodes
  • element and text nodes are most commons

Different types are with different methods and properties. If you want to play with the DOM fluently. You have to remember this.

Some useful Elements:

  • HTMLAnchorElement
  • HTMLBodyElement
  • HTMLButtonElement
  • HTMLCanvasElement
  • HTMLDivElement
  • HTMLDocument
  • HTMLFormElement
  • HTMLHeadingElement
  • HTMLHtmlElement
  • HTMLImageElement
  • HTMLInputElement
  • HTMLLIElement
  • HTMLLabelElement

Use instanceof method or tagName

It is good if you want to find multiple elements. For example:

  function findAllParagraphs() {
    var matches = [];

    document.body.childNodes.forEach(function(child) {
      if (child instanceof HTMLParagraphElement) {
        matches.push(child);
      }
    });

    return matches;
  }

  findAllParagraphs();

Traversing Nodes

parent Node Properties value
firstChild childNodes[0] or null
lastChild childNodes[childNodes.length-1] or null
childNodes Live collection of all child nodes
child node properties value
nextSibling parent.childNodes[n+1] or null
previousSibling parent.childNodes[n-1] or null
parentNode immediate parent of this node

Use recursive function to walk the dom

  // the Douglas Crockford's way
  function walkTheDOM(node, func) {
    func(node);
    node = node.firstChild;
    while (node) {
      walkTheDOM(node, func);
      node = node.nextSibling;
    }
  }

you can take a look how Douglas Crockford’s explanation

  // walk() calls the Function callback once for each node
  function walk(node, callback) {
    callback(node);

    for (var i = 0; i < node.childNodes.length; i++) {
      walk(node.childNodes[i], callback);
    }
  }

  walk(document.body, function(node) {
    console.log(node.nodeName);
  });

Get/Set Attributes

Method Description Returns
getAttribute(name) Retrieve value of attribute name Value of attribute as String
setAttribute(name, newValue) Set value of attribute name to newValue undefined
hasAttribute(name) Check whether element has attribute name true or false

use classList to modify class attribute.

classList is an array-like DOMTokenList object:

Name Description
add(name) Add class name to element
remove(name) Remove class name from element
toggle(name) Add class name to element if it doesn’t exist, remove if it does exist.
contains(name) Return true or false depending on whether element has class name.
length The number of classes to which element belongs.

use style to set css properties.

for example, we can do this: h1.style.color = 'blue'

Finding DOM nodes

in document, you can do with this, if there is an id attribute on an element.

  • document.getElementById(id): Element with specified id.
Method Returns
document.getElementsByTagName(tagName) HTMLCollection or NodeList of matching Elements
document.getElementsByClassName(className) HTMLCollection or NodeList matching Elements

There is something you should be careful:

  1. it returns a collection, if your are sure to get only one object, please use like collection[i] to retrive.
  2. if it is no select. it will return empty array-like
  3. use for(var i = 0;i < collection.length; i += 1) {} to iterate. This is not a real Array. :
  4. getElement*s*, there is an ‘s’.

use CSS selector

This works like in the css file, when you select the element in the HTML. Think you are using css:

Method Returns
document.querySelector(selector) First matching Element or null
document.querySelectorAll(selector) NodeList of matching Elements

It is Selector, not Select.

Traversing Elements

The DOM also provide some methods that let you retrive element directly, ignoring other Nodes like Text.

Parent Element Properties Value
firstElementChild children[0] or null
lastElementChild children[children.length-1] or null
children Live collection of all child elements
childElementCount children.length
Child Element Properties Value
nextElementSibling parentNode.children[n+1] or null
previousElementSibling parentNode.children[n-1] or null

Create/Move DOM

It is good to find them all. But what if you want to create a nodes? or you want to remove them?

Create new Nodes

Node Creation Method Returns
document.createElement(tagName) A new Element node
document.createTextNode(text) A new Text node
node.cloneNode(deepClone) Returns a copy of node

Add nodes to the exist DOM:

Parent Node Method Description
parent.appendChild(node) Append node to the end of parent.childNodes
parent.insertBefore(node, targetNode) Insert node into parent.childNodes before targetNode
parent.replaceChild(node, targetNode) Remove targetNode from parent.childNodes and insert node at its former position

If you want to insert nodes to its neighbor?

Element Insertion Method Description
element.insertAdjacentElement(position, newElement) Inserts newElement at position relative to element
element.insertAdjacentText(position, text) Inserts Text node containing text at position relative to element

Be aware that , you have to put a string with specific term in position:

Position Description
beforebegin Before the element itself
afterbegin Just inside the element, before its first child
beforeend Just inside the element, after its last child
afterend After the element itself

Remove them!

Good to add these Nodes. How about removing them?

Element Method Description
node.remove() Removes node from the DOM
parent.removeChild(node) Remove node from parent.childNodes

Let’s play with DOM

So you are with your weapons. You know how to find them, add/remove/change attribute, and you also know how to traversing the element; you also can find a specific nodes with class/id; even more, you can create and move the nodes!! With all these weapons. You know are able to play on any pages.

If we create a HTML just as the same DOM tree at the bigining, that’s play with this one:

  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>DOM Tree Example</title>
  </head>
  <body>
    <h1>Lorem ipsum</h1>
    <div>
      <p id='first'>

  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus efficitur in lectus ac sollicitudin. Aenean id fermentum ligula, sed volutpat ex. Sed leo tortor, dignissim ac tempor vitae, porta eleifend libero. Nam tristique vel nisi non dictum. Sed faucibus arcu nec magna ornare, porta laoreet nulla tristique. Maecenas id dapibus magna. Nulla ac ante nec eros pretium molestie. Fusce volutpat interdum massa, vitae tempor justo sollicitudin ut. Maecenas aliquam, diam et bibendum imperdiet, risus lacus facilisis purus, id dignissim ligula leo vel ipsum. Sed eget ornare quam. Etiam at justo id sem blandit aliquam. Mauris sed gravida velit. </p>
      <p id='second'>Phasellus malesuada dolor eget orci placerat euismod. Vestibulum mattis libero eget luctus vehicula. Fusce feugiat sapien a euismod sodales. Donec pellentesque consectetur pulvinar. Aenean non lectus nec ex hendrerit varius. Nunc a mauris a turpis ornare tincidunt. Morbi convallis porta augue. Donec orci justo, porta id lobortis in, rutrum ut tellus. Quisque rhoncus tempor ipsum, id lobortis purus ultrices a. </p>
    </div>
  </body>
  </html>

If you use the walk the dom, you will get:

      "BODY" //element 
      "#text"  //text
      "H1" //element
      "#text"
      "#text"
      "DIV"
      "#text"
      "P"
      "#text"
      "#text"
      "P"
      "#text"
      "#text"

If we want to add class='article' in the paragraph with id = 'first'. How to do with it?

  var fisrt = document.getElementById('first');
  first.setAttribute('class', 'article');

Then I want this paragraph’s color turn to blue?

  first.style.color = 'blue';

Then, I want to change this paragraph with the short content with ‘hello world’?

  first.textContent = 'hello world';

I also want add another div after the div that contains with the same content as first?

  var newDiv = document.createElement('div');
  newDiv.appendChild(first.cloneNode(true));
  var originDiv = first.parentElement;
  originDiv.insertAdjacentElement('afterend', newDiv);

Good, But I want to know how many p in this document?

  // use walk
  var count = 0;
  walk(document, function(node) {
    if (node.nodeName === "P") {
      count++;
    }
  });

  console.log(count);  //3 

Or we can use querySelectorAll:

  var paraList = document.querySelectorAll('p');
  paraList.length; //3

Of course, you can remove them!

  originDiv.removeChild(first);

If you play with them in your Chrome, now you have try to find them, walk through them, add more nodes, remove them. Besides, you also change there attributes.

Summary

This is some useful ways to manipulate DOMs. There are more way to use DOM in MDN documentation. But there are too many things there. If you want to quick get start with it. This is a short notes about how to use DOM methods.

to_param in Ruby on Rails

If I want a custom slug=======================I walk through this cutstom slug.1. create migration `add_slug` to add a column inside the...… Continue reading

What is ORM in Rails mean?

Published on July 14, 2017