Borking around with the HTML on your page is identical to borking around with XML; after all, HTML is XML, at its core. The only question is how to get your root element so you can start playing. The answer? document.documentElement, for most browsers. I can't speak for everyone, however. Frankly, there's little else to say. Simply crack open your browser's API (when in doubt, give Google a shout!) and see what its implementation has to offer. Chances are, you'll see some familiar faces; i.e., the various node functions you've already seen.
The only caveat is that you must generally withhold your page modifications until after the page load. The easy way to do this is with the onLoad event in the body tag, or, of course, via user interaction (button clicks, text change events, etc). Here's a brief HTML page that adds a paragraph tag after the page loads.
<html>
<head>
<title>Hello</title>
function doThis()
{
var body = document.documentElement.getElementsByTagName("body");
var paragraphNode = document.createElement("p");
var paragraphContents = document.createTextNode("Hello, world!");
paragraphNode.appendChild(paragraphContents);
body[0].appendChild(paragraphNode);
//insert code here later
}
</script>
</head>
<body onload="doThis()">
</body>
</html>
This will display "Hello, world!" on the page, but more importantly, it is actually plugging a paragraph node into the document tree. Let's play with our new paragraph's style now. There are a few ways to go about this, so we'll go ahead and use them both. We'll start with the XML-centric way; invoking the attribute as a simple node and fiddling with the value. We'll first create an attribute node, set its value, and then link it to our paragraph node. Then we'll decide that we want to add some other stuff, and -- what the heck -- have a look at what we've done to date. The following code is to be inserted into the comment in the above code block.
var attrib = document.createAttribute("style");
attrib.nodeValue = "color:red;";
paragraphNode.setAttributeNode(attrib);
var secondAttrib = paragraphNode.attributes[0];
secondAttrib.nodeValue += "background-color:blue;";
alert(paragraphNode.getAttribute("style"));
As you can see, we create an attribute node with the document.createAttribute function, which takes the attribute name as a parameter. The function doesn't care whether the attribute is valid HTML or not, so it will execute properly every time, but some (most or all...not sure which of the three) HTML parsers will check the validity of the HTML you're inserting an drop any illegal declarations and/or additions you make. So if you do something and it doesn't work, check your error console.
Anyways, we create an attribute and save a reference to it in a variable. We then set the nodeValue to a valid stylesheet attribute. Remember, no matter what part of the document tree to which you attach this node, future changes to the reference you have will be reflected. We then add it as an attribute to our paragraph node with the setAttributeNode, which takes an attribute node as a parameter.
Next, we'll create a new reference to the node (just because) by looking at the paragraph's attribute array. Be warned! Attributes define a very wide array of things in HTML. If you don't validate your attributes and just go by the order in which you set them, you're liable to get an attribute describing an event handler or some such. To prevent this, you can associatively invoke (my verbage...don't know what the method is really called!) the attribute via the following syntax:
paragraphNode.attributes["style"].nodeValue; paragraphNode.attributes.style.nodeValue;
As always, confirm compatibility before deploying! Back to the secondAttrib. We get a reference to the attribute node, append some more stuff to the node value (which is automatically reflected since the node is already linked into the tree) and then call the getAttribute function of the paragraphNode, which returns the value of the node named in the function parameter. The getAttribute function is the same as the nodeValue property, except the nodeValue property isn't read-only!
There is a more object-oriented approach to getting and setting style properties, however. Within each element node is a style object, from which you can get and set any style. For example:
paragraphNode.style.backgroundColor; paragraphNode.style.color;
The nomenclature for style attributes is the same, save for one different convention: where properties declared in stylesheets have dashes instead of spaces, they are camel cased here. That is, instead of a dash or a space, the dash-or-space is removed and the first letter of the next word is capitalized. So the phrase "look at me" becomes "lookAtMe" and the phrase background-color becomes backgroundColor, as exhibited above.
The mother of all properties, though, is a little gem called innerHTML. Present on all element nodes, it returns every trace of text between the opening and closing tags of the element to which it is affixed, be it added manually or programmatically -- exclusive of the tag itself, of course. Try it on a few of the element nodes we have created (i.e., body[0].innerHTML or paragraphNode.innerHTML) to see what you get! Strictly speaking, overuse of this is a cop-out, since you're basically discarding the object model to go back to 19th century string manipulation. And yes, you can set this property. And yes, that does include header tags and script tags, which means you can programmatically generate javascript code, were you so inclined.
And that just about does it for this lesson. This isn't quite Ajax yet (it is merely dynamic HTML at this point), but there's plenty to do with this functionality alone...well, at least there will be after the next lesson: events!