Javascript Guide - The DOM
You can now also navigate the guide through the table of contents.
So - you want to learn how to make your website interactive? Well, after a few other posts, it is time we learn how to play with the DOM.
the Document Object Model
WikipediaThe Document Object Model (DOM) is a cross-platform and language-independent convention for representing and interacting with objects in HTML, XHTML and XML documents
In javascript, there is a designated accessor to all of the DOM's API- the document object. The document object holds a reference to the root element of our document - the html tag, and also a long list of designated methods for manipulating the page.
Unfortunately, the DOM sucks. Although it holds great potential, at it's core, the DOM is awkward and bulky. In fact, this is why libraries like JQuery got their fame. But, in order to use JS you should at least be familiar with it.
So here follows a brief introduction to the DOM, and how we use it.
How does it work?
At it's core, the DOM is a tree-like representation of our page. Each element is a node. Every element contains references to It's parent and it's neighboring siblings, and an array of it's child elements.
The best way for you to see a representation of the DOM tree is for you to open the HTML tab in firebug.
Creating an Element
Element creating is done via the document.createElement method, and it receives 1 argument - the tag name:
var div = document.createElement('div');
console.log(div);
If we want to set attributes to our element, we do it via the element.setAttribute method:
div.setAttribute('id','some-id');
console.log(div);
And if we want to access an attribute - element.getAttribute:
console.log(div.getAttribute('id'));
So far so good - although the names are long (which means easier to misspell), they are meaningful and quite easy to remember. But what can we do with that element?
Well, for that we need to inject it. But first, we need to select a target. The best and fastest way is to use document.getElementById. This method receives one argument - an existing id from our page, and returns the element with that ID.
Now, we use the element.appendChild method to inject our newly created element. Below is an empty box with the id of example1.
var ex1 = document.getElementById('example1');
ex1.appendChild(div);
note - I've set a style to some-id so you can see it injected
So this wasn't too hard was it? well, what about adding some text to it? Well, there are two ways - the DOM way, and the hacky way.
-
The right way - document.createTextNode
You see - in the DOM, everything is a node. Text is no exception. So when we want to add text to our element, we first need to create a text node, and then append it to our element:
var div = document.createElement('div') , text = document.createTextNode('i am just some random text'); div.appendChild(text); //notice that i used a nice aspect of the DOM - chaining - all methods of the DOM return a node, //so i can chain multiple methods one after the other: document.getElementById('example2').appendChild(div);run code -
The easy way -
innerHTMLinnerHTMLis a string representation of our element's inner html. As it is a string, we can do all stringy stuff to it, like assignment and concatenation. For quick operation, it is quite useful, and much faster than normal DOM manipulations.var div = document.createElement('div'); div.innerHTML = "im created using the easier method!"; document.getElementById('example3').appendChild(div);run code And if that wasn't enough - there is more - we can use it to nest elements - by simply writing their HTML:
var div = document.createElement('div'); div.innerHTML = "<strong>im created using the easier method!</strong>"; document.getElementById('example4').appendChild(div);run code
Now, you might ask yourself - why ever use the first way? why use any of this if we can simply write html?
Well, there are a few answers to that question:
- The first is that there usually isn't. In fact, this is pretty much the standard way to create elements in JQuery.
- But, in fact, it is quite cool to be able to handle our elements like first class objects, and not just strings, and it is in fact how the browser sees them.
- To extend the last point - if we want to do stuff other than create elements and put text in the, the DOM is the only way to do it. In order to move an element around, to make it disappear, to change it's color etc., you will first need to get a reference to it. And for that you need at the very least a reference to that element's node. Every single manipulation we perform on our elements will require DOM manipulation.
Traversing The DOM
As mentioned before, every node holds 3 pointers - one to it's parent, one to it's previous element, and one to it's next. For this example, we will use the following list. It's second element's ID is li-2.
- I'm 1
- I'm 2
- I'm 3
var li = document.getElementById('li-2');
console.log('parent:', li.parentNode);
console.log('previous:', li.previousSibling);
console.log('next:', li.nextSibling);
Lastly, to wrap up our traversal tools (yes - at it's core we get only 4...) - we have childNodes, which, as it name (might) imply, holds an array of all the elements children:
console.log(document.getElementById('li-example').childNodes);
Now, if you looked at your console, you might have noticed something quite annoying - since text is also a node, most of the time, the next and previous siblings of an element (at least in a well styled document) are whitespaces. Remember when I said the DM was crap?
One last thing - removing an element -
var div = document.getElementById('example5')
, strong = document.getElementById('str1');
div.removeChild(strong);
We now know everything there is to know about the DOM.
Well... OK. So you might want to play with you element's styles.
Styling via the DOM
Well, there are 2 stages for playing with styles - setting a style and retrieving it. Retrieving, is actually very not straight forward, and the best I can do is to point you to an external reference. But for setting them, it's much much simpler.
Every element has a style property, which contains an array of all the styles possible. All styles names are camelCased (so, for example, margin-top becomes marginTop). The style property is linked to the element's style attributes. This means that once a style is set on that attribute, it is accessible through the property, and that once setting a style, it will appear in the style attribute.
Confused? Example to the rescue!
For this example we will use the following element:
<div id='example6' style="border:1px solid; background:#fca; width:100px; height:100px;"></div>
note - as with js - i highly encourage you not to use inline styling. this one is just used for making a point.
var div = document.getElementById('example6');
console.log(div.style.borderColor);
div.style.backgroundColor = '#cae';
Now, you might have noticed that the color was returned as an rgb string. Not very useful? too bad.
So, with all the above tools, we've learned a few things:
- The DOM sucks. Although it is quite a useful concept, it's implementation sucks, and I highly encourage you, once we are done with our guide (not too far away now - 2-3 more posts) that you do ahead and find yourself a nice framework to work with (more on that later on).
- If that wasn't enough to convince you, I will point that the DOM is not cross-browser. I've only touched basic tools on this post, but if you read the link I pointed you to - you'll learn that every browser implements the DOM differently. In fact, the DOM is the number two source for cross-browser problems (CSS being the first off course).
- How to use the DOM to create, find and manipulate your elements.
But we're not done with the DOM yet. On the next post, we will learn about the one thing that does shine with the DOM - it's event system.