Anne van Kesteren

Scriping lesson 1

Lot's of people know JavaScript a little bit. They know for example document.write(). More difficult, but more forward compatible is using the Document Object Model (DOM) from the W3C in combination with JavaScript. How do we use it? The DOM has a couple of basic function, which you should know if you want to it. For example, how do we locate the body element? In good old JavaScript everybody know it: document.body, using the DOM we do the following: document.getElementsByTagName('body')[0]. Shocked? That adds quite a bit of bytes. getElementsByTagName is a function which returns a nodeset. So if we enter img we get all the img elements returned in an array. The first in that array is the first one you come across when you view source. If we enter body it will return an array with one value in it, since normal documents have only one body element. If we want to select this single element in that array we use [array-number]. array-number is the location inside the array. In most scripting languages the first value in the array is equal to '0'. So now you understand that function I hope :). You can also select the body element like this: document.getElementsByTagName('body').item(0), but that takes even more bytes, so I don't use it anymore.

The next function looks very similar to the first: document.getElementById('id-attribute-value'). Note that it is Element and not Elements, this can be confusing, but it is actually a quite simple rule. This function returns a single node that has the id-attribute-value, it does not return an array.

A small example of how we could use this. Consider we use a span element to change our background color (later you will learn how to create the span with JavaScript, so totally separating scripting from actual important content):

<span onclick="changeBackgroundColor('red');">Change the background color to red</span>

The JavaScript code behind this could look like this:

function changeBackgroundColor(color){
 document.getElementsByTagName('body')[0].style.backgroundColor = color;
}

As you can see we use style to combine the element with property. You can use all the CSS properties but you have to keep in mind that the first letter after a hyphen (-) should be transformed into uppercase and there should be no spaces in the property. In this example color is the variable. It doesn't get double quotes around it, because then it wouldn't be a variable anymore. Basically variables and strings work this way:

Now consider we have the following XHTML document:

<!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" xml:lang="en">
<head>
 <title>Generate content with JS</title>
 <script type="text/javascript" src="script.js"></script>
</head>
<body>
 <p></p>
</body>
</html>

I agree it is quite minimal, but it serves our needs for a simple example. We are going to create the span element with JavaScript and add it inside the p element. The 'script.js' file should look like the following:

function changeBackgroundColor(color){
 document.getElementsByTagName('body')[0].style.backgroundColor = color;
}
function createSpan(){
 var s = document.createElement('span');
 var sc = document.createTextNode('Change the background color to red');
 s.appendChild(sc);
 s.onclick = function(){
  changeBackgroundColor('red');
 }
 document.getElementsByTagName('p')[0].appendChild(s);
}
window.onload = function(){
 createSpan();
}

The variable 's' is the span element. 'sc', which stands for span content, is the content of the span element, not to hard, it is? We append the content to the span element with appendChild, which we also use to append the span element to the document. I think you will understand the rest. If you have any questions, don't be afraid to ask them, I will try to answer them as correct as possible (for me :)).

Comments

  1. Ok, let's get forward compatible. :) How should I make this right?

    document.write('<style type="text/css">div.panel{display:none;}</style>');

    Posted by I. G. at

  2. I don't like script requests, but because your intenstions are good (I hope), I will give you a possible answer this time. I think there are better ways using the CSSDOM, but I didn't look into that yet, besides that it is probably not as good supported as this.

    function hide(){
     var div = document.getElementsByTagName("div");
     for(var i = 0; i < div.length; i++){
      if(div[i].getAttribute("class") == "panel"){
       div[i].style.display = "none";
      }
    }

    This function is an onload function, just as createSpan. BTW, I haven't tested it.

    Posted by Anne at

  3. In just this specific case, you should use .className instead of .getAttribute() because of iew incompatibilities.

    As for your article, I can think of one reason for using .item(iIndex) instead of [iIndex]. That reason would be that you can iterate through the .item(iIndex) easier than through [iIndex] because .item(iIndex) will generate null when you've reached an index that does not exists, while the [iIndex] syntax generates undefined.

    // Iterate through a DOMCollection
    var
        o,
        i=0,
        divs=document.getElementsByTagName('div');
    while((o=divs.item(i++)))
        o.style.display='none';
    alert('Number of divs: '+i);
    

    Posted by liorean at

  4. Anne,

    Thanks for the reply, be sure that my intentions are extremely good, ie. going up from XHTML1 Strict to 1.1 Strict. Regarding your answer, it seems to me that getElementsByTagName doesn't work in IEs... Maybe I should try this create/append stuff to build up the style tag...

    Posted by I. G. at

  5. Uhm, I was wrong. getElementsByTagName works, .className is needed in IE. Thanks, liorean!

    Posted by I. G. at

  6. Pleased to be of service ;)

    As for getElementsByTagName, it is supported, but the * wildcard isn't, in IE5.0W. That was fixed in IE5.5W IIRC.

    Posted by liorean at

  7. For example, how do we locate the body element? In good old JavaScript everybody know it: document.body, using the DOM we do the following: document.getElementsByTagName('body')[0]. Shocked? That adds quite a bit of bytes.

    Of course, you could always remap the fancy junk to a var, this can save a lot of bytes if it is used a lot. Here's an example:

     var getTag = document.getElementsByTagName;
     var aVar = getTag('body')[0];
     var anotherVar = getTag('title')[0];
     var imgArray = getTag('img');
    

    Posted by Jimmy C. at