Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

JavaScript and the DOM Series: Lesson 1

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

Hello and welcome to the first part of what will hopefully be an extensive series covering core aspects of the JavaScript programming language and the DOM API.

While frameworks such as jQuery, Prototype and MooTools are great ways of suppressing browser bugs and speeding up development, it's important to know and understand the underlying technologies. This series intends to tell you what you need to know about JavaScript and the Document Object Model (DOM). Even if you swear by a particular library this will still benefit you - knowing how something works under the skin can only be a good thing!

Introductions

JavaScript

JavaScript is a dynamic, loosely typed, prototype-based programming language which is used in many different environments. As well as being the prevalent client-side programming language of the web, it's also used to write plugins for IDEs, in PDF files and as a basis for other platforms and higher abstractions.

JavaScript is based on the ECMAScript standard (ECMA-262) and was created by Brendan Eich of Netscape. It was originally called LiveScript but it was later renamed to JavaScript, probably with the sole intention of causing confusion.

Here are some of its features in a little more detail:

  • Dynamic programming languages execute at runtime; they are not compiled. Because of this, JavaScript is sometimes considered a scripting language as opposed to a true programming language (obviously a misconception). When you have JavaScript within an HTML document it will be parsed as the page loads within the browser, hence at "runtime".
  • Loosely typed languages do not insist upon any strong typing system. If you've programmed in C or Java (not the same as JavaScript) you'll know that when declaring a variable you have to specify a type such as 'int' (integer). JavaScript is different in that you don't need to specify the type.
  • To perform inheritance within JavaScript you have to use something called prototypes. JavaScript does not support classes.
  • JavaScript is also a functional language. It treats functions as first-class objects; this is the idea behind lambda.

Understanding the above points is not important in learning about JavaScript; it's just a few ideas to get your brain in gear, and should help you differentiate JavaScript from other programming languages you may have experienced.

Document Object Model

The Document Object Model, normally abbreviated to DOM, is the API through which JavaScript interacts with content within a website. JavaScript and the DOM are usually seen as a single entity since JavaScript is most commonly used for this purpose (interacting with content on the web). The DOM API is used to access, traverse and manipulate HTML and XML documents.

Typical structure of a DOM hierarchy
A basic outline of the typical DOM hierarchy (Simplified)

Here's a few noteworthy things about the DOM:

  • The window object serves as the global object, you access it by just typing "window". It's within this object that all of your JavaScript code is executed. Like all objects it has properties and methods.
    • A property is a variable stored under an object. All variables created on a web-page authomatically become properties of the window object.
    • A method is a function stored under an object. Since all functions are stored under (at least) the window object they can all be referred to as 'methods'.
  • The DOM creates a hierarcy corresponding to the structure of each web document. This hierarchy is made up of nodes. There are several different types of DOM nodes, the most important are 'Element', 'Text' and 'Document'.
    • An 'Element' node represents an element within a page. So if you have a paragraph element ('<p>') then it can be accessed through the DOM as a node.
    • A 'Text' node represents all text (within elements) within a page. So if your paragraph has a bit of text in it can be directly accessed through the DOM.
    • The 'Document' node represents the entire document. (it's the root-node of the DOM hierarchy/tree).
    • Also note that element attributes are DOM nodes themselves.
  • Each layout engine has a slightly different implementation of the DOM standard. For example, the Firefox web browser, which uses the Gecko layout engine, has quite a good implementation (although, not entirely inline with the W3C specification) but Internet Explorer, which uses the Trident layout engine is known for it's buggy and incomplete implementation; a cause of much anguish within the web development community!

Download Firebug

If you're using Firefox and you don't already have the Firebug addon I recomend you download and install it now. It's a very useful tool for getting a decent picture of the entire document structure.

JavaScript on the Web

The Script Element

When you want to use JavaScript on a website it has to be included within a SCRIPT element:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
    <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>JavaScript!</title>
    </head>
    <body>
    
        <script type="text/javascript">
        // <![CDATA[
       
        // ]]>
        </script>
    
    </body>
</html>

As you can see we've got a SCRIPT element at the bottom of our document. The TYPE attribute should strictly be set to 'application/javascript' but to no surprise that doesn't work in Internet Explorer so we're stuck with either 'text/javascript' or no TYPE attribute at all. If you care about validation then the former suggestion will probably suit you.

Specify CDATA if you're using XHTML

Remember to specify your scripts as CDATA!

You'll also have noticed that within that SCRIPT element we have a couple of commented-out lines. These inform XHTML-supporting browsers that the content of the SCRIPT element is 'character data' and should not be interpreted as XHTML markup. It's only really necessary if you plan on using either the '<' or '>' characters in your JavaScript code. Obviously you can forget about all this if you're using plain HTML.

The Defer Attribute

Any JavaScript we put inside that SCRIPT element will run as the page loads. The only exception is when a SCRIPT element has a 'defer' attribute. By default, when a browser meets a SCRIPT element, it will stop and run the code, then it will carry on parsing the document. The DEFER attribute informs the browser that the code contains no document-altering code and so can be run later. The only problem with this is that it only works in IE, so it's probably best to avoid this attribute.

Linking to External Scripts

If you want to link to an external script file then simply add an SRC attribute to your SCRIPT element corresponding to its location. It's normally a better idea to have seperate script files than to write code inline as it means the browser can cache the file. Plus you don't need to worry about any of that CDATA nonsense:

<script type="text/javascript" src="my-script.js"></script>

JavaScript essentials

Before we continue with the DOM it's a good idea to have a basic grasp of some JavaScript essentials. If you have trouble understanding some of these, don't worry - you'll eventually pick them up!

In JavaScript you can have different types of values. There are Numbers, Strings, Booleans, Objects, Undefined and Null:

Single-line comments are written using two forward slashes (//), all remaining text on that line is assumed to be a comment by the parser. Multi-line comments are signified using '/*' and '*/' to finish the comment.

Numbers

In JavaScript all numbers are represented as floating-point values. When defining a number variable remember not to wrap it in any quotes.

// Note: ALWAYS use 'var' to declare a variable:
var leftSide = 100;
var topSide = 50;
var areaOfRectangle = leftSide * topSide; // = 5000

Strings

Any string you define is taken literally, JavaScript will not process it. A string is a sequence of Unicode characters and should be wrapped in a matching pair of either single or double quotes.

var firstPart = 'Hello';
var secondPart = 'World!';
var allOfIt = firstPart + ' ' + secondPart; // Hello World!
// The + sign is used as the string-concatenation operator
// (it's also used for numerical addition)

Booleans

Boolean types are useful when you want to evaluate a condition - to see if it meets a specified criteria. There are only two possible Boolean values: true and false. Any comparison, using logical operators, will result in a Boolean.

5 === (3 + 2); // = true 
// You can assign Boolean values to variables:
var veryTired = true;
// You can test for it like this:
if (veryTired) {
	// Sleep
}

The '===' you see above is a comparison operator, we'll cover them later.

Functions

A Function is a specialised Object:

// Using the function operator to create a new function:
function myFunctionName(arg1, arg2) {
	// Function code goes here.
}
    
// If you omit the function's name then
// you're creating an "anonymous function":
function(arg1, arg2) {
	// Function code goes here.
}
        
// Running a function is simply a case of referencing it
// and then adding a parenthesis (with arguments):
myFunctionName(); // No arguments
myFunctionName('foo', 'bar'); // with arguments
    
// You can also run a function without assinging
// it to a variable:
    
(function(){
    // This is known as a self-invoking anonymous function
})();

Arrays

An Array is also a specialised object and can contain any number of data values. To access data values within an array you must use a number, referred to as the 'index' of the item you're trying to retrieve:

// 2 different ways of declaring a new array,
    
// Literal:
var fruit = ['apple', 'lemon', 'banana'];
    
// Using the Array constructor:
var fruit = new Array('apple', 'lemon', 'banana');
    
fruit[0]; // Access the 1st item of the array (apple)
fruit[1]; // Access the 2nd item of the array (lemon)
fruit[2]; // Access the 3rd item of the array (banana)

Objects

An Object is a collection of named values (key - value pairs). It's similar to an array, the only difference is that you can specify a name for each data value.

// 2 different ways of declaring a new Object,
    
// Literal (curly braces):
var profile = {
	name: 'Bob',
    age: 99,
    job: 'Freelance Hitman'
};
    
// Using the Object constructor:
var profile = new Object();
profile.name = 'Bob';
profile.age = 99;
profile.job = 'Freelance Hitman';

If/Else Statement

One of the most common constructs in JavaScript is the 'IF' / 'ELSE' statement. It goes something like this:

var legalDrinkingAge = 21; 
var yourAge = 29;
    
if ( yourAge >= legalDrinkingAge ) {
	// We can use 'alert' to notify the user:
    alert('You can drink.');
} else {
	alert('Sorry, you cannot drink.');
}

JavaScript Operators:

Instead of listing them all out here I suggest you visit the MDC article on Operators. It explains them in a lot of detail. I've setup a few examples to give you an idea of how some of the operators are used below:

// additioa/substraction/multiply/divide
var someMaths = 2 + 3 + 4 - 10 * 100 / 2;
    
// Equality
if ( 2 == (5 - 3 ) { /* Do stuff */ } // == checks for eqaulity
    
// Inequality
if ( 2 != (5 - 3 ) { /* Do stuff */ } 
    
// Strict Equality operators:
// (I suggest using these)
2 === 2 // Instead of 2 == 2
2 !== 3 // Instead of 2 != 3
    
// Assignment:
var numberOfFruit = 9;
numberOfFruit -= 2; // Same as "numberOfFruit = numberOfFruit - 2"
numberOfFruit += 2; // Same as "numberOfFruit = numberOfFruit + 2"

Looping

Looping is useful when you need to go through all items in an array or all members of an object. The most common way to loop in JavaScript is by using either the FOR or WHILE statement.

var envatoTutSites = ['NETTUTS','PSDTUTS','AUDIOTUTS','AETUTS','VECTORTUTS'];
    
// WHILE loop
var counter = 0;
var lengthOfArray = envatoTutSites.length;
while (counter < lengthOfArray) {
    alert(envatoTutSites[counter]);
    counter++; // Same as counter += 1;
}
    
// FOR loop
// (The i stands for "iterator" - you could name it anything)
for (var i = 0, length = envatoTutSites.length; i < length; i++) {
    alert(envatoTutSites[i]);
}
About the FOR loop in JavaScript

FOR loops are more popular for looping through Arrays.

Back to the DOM

Accessing DOM nodes

Let's assume we have a basic XHTML document containing a paragraph and an unordered list:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
    <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>JavaScript!</title>
    </head>
    <body>
     
        <p id="intro">My first paragraph...</p>
    
        <ul>
            <li>List item 1</li>
            <li>List item 1</li>
            <li>List item 1</li>
            <li>List item 1</li>
            <li>List item 1</li>
        </ul>
    
        <script type="text/javascript">
        // <![CDATA[
       
        // ]]>
        </script>
    
    </body>
</html>

In this first example we're going to access our paragraph by using the 'getElementById' DOM method:

(This code goes within the SCRIPT element in the above template).

var introParagraph = document.getElementById('intro');
// We now have a reference to the DOM node. This DOM
// node represents the intro paragraph.

The variable 'introParagraph' is now a reference to the DOM node. We can do a number of things with this node, - we can query its content and attributes, and can manipulate any aspect of it. We can remove it, clone it or move it to other parts of the DOM tree.

Anything which is present within a document we can access using JavaScript and the DOM API. So, we might want to access the unordered list in a similar fashion, the only problem is that it doesn't have an ID. You could give it an ID and then use the same method as above or we could access it using 'getElementsByTagName':

var allUnorderedLists = document.getElementsByTagName('ul');
// 'getElementsByTagName' returns a live node collection/list
// - It's very similar to an array with a few slight differences.

getElementsByTagName

The 'getElementsByTagName' method returns a live node collection/list. It's similar to an array in that it has a length property. One important thing to note is these collections are "live" - if you add a new element to the DOM then the collection will update itself. Since it's an array-like object we can access each node via an index, from 0 to the total length of the collection (minus 1):

// Access single unordered list: [0] index
var unorderedList = document.getElementsByTagName('ul')[0];
    
// Create Node list of all list items within the UL:
var allListItems = unorderedList.getElementsByTagName('li');
   
// Now, we can loop through each list item using a FOR loop:
for (var i = 0, length = allListItems.length; i < length; i++) {
    // Extract text node within and alert its content:
    alert( allListItems[i].firstChild.data );
}
Accessing nodes and attributes within the DOM

Accessing nodes and attributes within the DOM

Traversing the DOM

The term "traverse" is used to describe the action of travelling through the DOM, finding nodes. The DOM API gives us plenty of node properties which we can use to move up and down through all the nodes within a document.

These properties are inherent of all nodes and enable you to access related/close nodes:

  • Node.childNodes: You can use this to access all direct child nodes of a single element. It will be an array-like object, which you can loop through. Nodes within this array will include all the different node types including text nodes and other element nodes.
  • Node.firstChild: This is the same as accessing the first item in the 'childNodes' array ('Element.childNodes[0]'). It's just a shortcut.
  • Node.lastChild: This is the same as accessing the last item in the 'childNodes' array ('Element.childNodes[Element.childNodes.length-1]'). It's just a shortcut.
  • Node.parentNode: This gives you access to the parent node of your current node. There will only ever be one parent node. In order to access the grandparent you would simply use 'Node.parentNode.parentNode' etc.
  • Node.nextSibling: This gives you access to the next node on the same level within the DOM tree.
  • Node.previousSibling: This gives you access to the last node on the same level within the DOM tree.
Traversing the DOM

Traversing a document (Simplified - please read below)

So, as you can see, traversing the DOM is incredibly easy, it's just a case of knowing the property names.

One thing to note about the above graphic: the list items can only be retrieved in that fashion if there is no whitespace between them. Because you can have text nodes and element nodes in a document the space in between the '<ul>' and the first '<li>' actually counts as a node itself. Similarily the unordered list is not actually the paragraph's next sibling - since it's on a new line there is space between the two elements - hence, another node! Normally, what you'd do in this situation would be to loop through the 'childNodes' array and test the 'nodeType'. A 'nodeType' of 1 means it's an element, 2 means it's an attribute, 3 means it's a text node. You can see a full list here: https://developer.mozilla.org/En/DOM/Node.nodeType.

That's all it is!

This is how all major JavaScript libraries work behind the scenes; using native DOM methods and properties to give you access to these elements through a nicely polished abstraction. What seperates you from the framework diehards is that you now have some idea of how to survive without a framework (if you didn't already)!

Until Next Time...

Well, that's it for part one. I hope you've learnt something from all my ramblings. In the next part of the series we'll hopefully be focusing on some more applicable examples; we'll probably be covering the browser event model as well.

In the mean time and if you haven't already then check out these talks by Doug Crockford (Yahoo! Video site):

Thanks for reading!

  • Subscribe to the NETTUTS RSS Feed for more daily web development tuts and articles.


Advertisement