Another Way To Access An Element (node Mantığı)
Html taglarına erişiminin farklı bir yolu
document.getElementById(ID)
We can also access element nodes with document.getElementsByTagName(tagName)
That returns an array of elements with that tagName.
Example: document.getElementsByTagName("TD").item(0)
In the example, we grab the first table cell (<td> tag) in the document. To get an array of all tags in the document, we can use:
document.getElementsByTagName("*")
So, to access the <body> tag, we can use: document.getElementsByTagName("BODY").item(0)
Not so fast...
Before applying the information provided in the past two sections, it's important to recognize two caveats. (I gratefully acknowledge the contribution of a colleague, Patrick Brennan, for pointing these out.)
1. You cannot realistically reference document nodes by anything other than the id attribute in HTML (XML is OK). IE5 and NS6 both insert spurious text nodes between the ones you have written (NS6 more than IE5).
2. <p> elements cannot be stacked according to the HTML 4.01 specification. As stated by the Consortium, "The P element represents a paragraph. It cannot contain block-level elements (including P itself)."
What he means is that it's really unrealistic to access an element by using it's relation to another one (with parentNode, firstChild, previousSibling, etc...). And lastly, he is saying that <p> elements should not be contained within another <p> element.
On to the example
Let's look at an example of referencing each element in different ways. Consider this page:
<body>
<ol id="ol1">
<li id="li1">
<span id="span1">
This is Text 1
</span>
</li>
<li id="li2">
<span id="span2">
This is Text 2
</span>
</li>
<li id="li3">
<span id="span3">
This is Text 3
</span>
</li>
</ol>
</body>
Now, we can access the ol1 tag by a number of ways (remember, these may be
ineffective because of "spurious text nodes"):
* document.getElementById("ol1")
* document.getElementsById("li1").parentNode
* document.getElementsByTagName("ol").item(0)
* document.getElementsByTagName("li").item(0).parentNode
* document.getElementsByTagName("li").item(1).parentNode
* document.getElementsByTagName("l1").item(2).parentNode
* document.getElementsByTagName("span").item(2).parentNode.parentNode
* document.getElementsByTagName("body").item(0).childNodes.item(0)
* document.body.childNodes.item(0)
Because we'll probably access the <body> tag a lot, we can use a shortcut (rather than using it's tagName like this: document.getElementsByTagName("BODY").item(0)
or by assigning it an ID and using that):
document.body as used above.
To access l2, we could use:
* document.getElementById("l2")
* document.getElementById("l1").nextSibling
* document.getElementById("l3").previousSibling
* document.getElementsByTagName("li").item(1)
* document.getElementsByTagName("span").item(1).parentNode
* document.getElementsByTagName("span").item(2).parentNode.previousSibling
* document.getELementsByTagName("ol").childNodes.item(1).parentNode.childNodes.item(1).parentNode.childNodes.item(1)
* document.getElementsByTagName("body").item(0).firstChild.firstChild.nextSibling
* document.body.childNodes.item(0).lastChild.previousSibling
Try to find the text node containing the following text--"This is Text 3."
We could find it by first accessing span3, and then accessing it's firstChild
. Example:
document.getElementById("span3").firstChild
Before, I said attributes were somewhat nodes. This is why they don't show up when you try to access an element's child nodes. Later, we'll look at how to change, set, and remove attributes; but before that, let's move on to some other essentials we can access from an element node.
Here's our sample page again:
<body>
<ol id="ol1">
<li id="li1">
<span id="span1">
This is Text 1
</span>
</li>
<li id="li2">
<span id="span2">
This is Text 2
</span>
</li>
<li id="li3">
<span id="span3">
This is Text 3
</span>
</li>
</ol>
</body>
hasChildNodes()
returns a Boolean value of true or false if the node has child nodes. For instance, if we said:
document.getElementById("span3").hasChildNodes()
that would return true, but if we said:
document.getElementById("span3").firstChild.hasChildNodes()
it would return false because that doesn't have any children (a text node can never have any children).
nodeName
returns the "name
" of a node:
document.getElementById("span3").nodeName
returns "SPAN
"
tagName
returns the tagName of an element.
document.getElementById("span3").tagName
returns "SPAN
"
You may be asking yourself what's the difference between nodeName
and
tagName
. Well, if you access a text node's tagName
, there is no
tagName
because it's not a tag (this only works for elements), but if you access a text node's
nodeName
, it will give you "#text." Thus:
returns
document.getElementById("span3").firstChild.nodeName "#text"
while document.getElementById("span3").firstChild.tagName
returns "undefined."
document.getElementById("span3").firstChild.nodeName
returns "#text" document.getElementById("span3").firstChild.tagName
returns "undefined."
nodeType
tells you what type of node an element is. It returns 1, 2, or 3.
- It returns 1 if it's an element
- It returns 2 if it's an attribute
- It returns 3 if it's text
document.getElementById("span3").nodeType
returns 1, while
document.getElementById("span3").firstChild.nodeType
returns 3. We won't really examine a nodeType
of 2 in this tutorial as it could get a little complicated.
nodeValue
returns value of the node. You can use this to retrieve or change this value. If the node is a text node (nodeType of 3)
, it returns the text; if it is an attribute (nodeType of 2)
, it returns the value of that attribute; if it's an element (nodeType of 1)
, it returns null. Text will return it's value:
document.getElementById("span3").firstChild.nodeValue
returns "This is Text 3,"
while an element returns null:
document.getElementById("span3").nodeValue
returns null.
Now, let's learn about attributes.
As stated earlier, everything on a page (including attributes) is a node. Unlike what you might have thought, attributes are not considered to be children of the element they apply to. Here, we'll look at how to retrieve, set, and remove attributes. Consider this sample element:
<iframe id="myIFrame" src="aDog.html" align="center" width="400" height="200"></iframe>
This can be accessed through document.getElementById("myIFrame")
. Now, let's take a look at how to access the attributes of this element.
getAttribute(attribute)
takes one argument, the attribute to retrieve, and returns it's value. Example:
document.getElementById("myIFrame").getAttribute("width")
return "400"
setAttribute(attribute, newValue)
takes two arguments, the attribute whose value you want to change (or create), and it's new value.
Example:
document.getElementById("myIFrame").setAttribute("width","200")
Now, myIFrame's width is 200. Note the use of quotes even on integers. This is because element attributes should always be a string (although they'll usually accept it even if it's not a string). We could also change this <iframe>
's src attribute with:
document.getElementById("myIFrame").setAttribute("src","someNewPage.html")
removeAttribute(attribute)
takes one argument, the attribute to be removed. Example:
document.getElementById("myIFrame").removeAttribute("width")
would remove the "width" attribute, and it would set it to the browser's default width for <iframe>
's.
And that's really all there is to know about attributes without going into very boring and gory details on them. Now, let's see how we can create element nodes out of thin air.
Beyond working with existing nodes and their methods and properties (hasChildNodes(), innerText, children,
etc.
)
, we can also create new nodes.
document.createElement(tagName)
creates a new element node with the specified tagName. It's amazing...you can create it just out of thin air...neat, huh? It accepts one argument, the tagName to create. Here's an example:
newSPAN = document.createElement("SPAN");
Notice that createElement()
can only be run from the "document," and that you should store this new element node in a variable.
Later, we'll learn what to do with this new element and how to append (or insert) it into the document.
document.createTextNode(text)
creates a new text node. It takes one argument, the "text" for the text node. Here's an example:
newText = document.createTextNode("This is the new text");
Note that this doesn't accept HTML, but only text (In other words, HTML tags will be interpretted literally--just as regular text).
Now, let's learn how to insert this text node and the new element we just created.
Insert Nodes into document
appendChild(newNode) inserts the new node to the end of the list of children of the node where this is run from. Take a look at the example if I've already lost you. It takes on argument, the new node to append. I know that it sounds difficult, but it's not. Here's an example, but first, we'll need some elements, so we can insert our new node after them.
<body>
<div align="center" id="div1">
<span id="span1">This is the text of SPAN1</span>
This text is not in a span tag.
</div>
</body>
newSPAN.appendChild(newText);
document.getElementById("div1").appendChild(newSPAN);
alert(document.getElementById("div1").lastChild.nodeName);
What we've done is we've appended the text node as the last child of the newSPAN node. Then, we've appended the newSPAN node as the last child of the div1 node. Now, it generates an alert message of "SPAN," whereas before we appended the new element node, we'd have gotten an alert message of "#text." Also note that we appended the text node we created to the <span> tag before in turn appending that <span> tag to "div1" in the document. We could have appended the <span> tag and then appending the text node to it if we wanted to, like so:
document.getElementById("div1").appendChild(newSPAN);
document.getElementById("div1").lastChild.appendChild(newText);
alert(document.getElementById("div1").lastChild.nodeName);
insertBefore(newNode, beforeNode) is similar to appendChild() except, instead of automatically inserting the new node as the last child, it will insert the new node before another one you specify. So, it accepts two arguments:
- The new node to insert
- The node to "insert it before"
So, in our previous example, let's say we wanted a new element, "SPAN2", directly before our "SPAN1"element. First, we must create the new element node:
SPAN2 = document.createElement("SPAN");
Now, we must access the "SPAN1" element to tell it to insert it before (there are numerous ways, but we'll only examine and use on of them):
SPAN1 = document.getElementById("div1").lastChild
From there, we can use the insertBefore() method to append it to the appropriate place:
document.getElementById("div1").insertBefore(SPAN2,SPAN1);
or
document.getElementById("div1").insertBefore(SPAN2,document.getElementById("div1").lastChild);
or
document.getElementById("div1").insertBefore(document.createElement("SPAN"),document.getElementById("div1").lastChild);
Also note that I called the insertBefore() method from the parent node of where I wanted to insert it before, because that is the node whose child list I am changing. Got it?
Dolly
cloneChild(node) is a function that copies and returns a node. It accepts one argument, whether to copy "deep." I'll explain this in the following example:
<body>
<div id="div1">
<span id="span1">This is the text of SPAN1</span>
<span id="span2">This is the text of SPAN2</span>
This text is not in a span tag.
</div>
</body>
Now, let's say we go:
div2=document.getElementById("div1").cloneNode(false)
It just copies <div id="div1"></div>, and it copies nothing between. Note that it copies the attributes of the node, also. Now, we can add attributes, remove attributes, add children, remove children, append that node anywhere on the document, etc....
Now, if we had run div2=document.getElementById("div1").cloneNode(true), it would copy the child nodes of "div1", and it would copy:
<div id="div1">
<span id="span1">This is the text of SPAN1</span>
<span id="span2">This is the text of SPAN2</span>
This text is not in a span tag.
</div>
If we don't define the "deep" argument as false or true, it is automatically false. Now, once a node is cloned, we could change it's attributes, child nodes, append it, etc...
Disappear...
removeChild(node) removes the node passed by it's sole argument. Note that this method (just like the others mentioned here) is run from the parent of the node you want to remove. Example:
<span id="span1">This is the text of SPAN1</span>
<span id="span2">This is the text of SPAN2</span>
This text is not in a span tag.
</div>
Now, we run: document.getElementById("div1").removeChild(document.getElementById("span2")), and it removes the "span2" node and its child nodes, leaving our document looking like:
<span id="span1">This is the text of SPAN1</span>
This text is not in a span tag.
</div>
replaceChild(newChildNode, oldChildNode) replaces the oldChildNode node with the newChildNode node. Example:
<span id="span1">This is the text of SPAN1</span>
This text is not in a span tag.
</div>
Now, we run:
newSPAN = document.createElement("SPAN");
newSPAN.setAttribute("id","span2");
newSPAN.setAttribute("align","center");
newText = document.createTextNode("This is the text of SPAN2");
newSPAN.appendChild(newText);
div1 = document.getElementById("div1");
div1.replaceChild(newSPAN,div1.firstChild);
and now, our changed document looks like:
<span id="span2" align="center" >This is the text of SPAN2</span>
This text is not in a span tag.
</div>
Those are the major methods and properties of the W3C DOM Level 1 (the Consortium's first Document Object Model recommendations). Let's look briefly at some aspects of W3C DOM Level 2.
When we used innerHTML to change the text in NN 6, it worked, but this is not the W3C recommended way. In fact, innerText, outerText, and outerHTML aren't supported by Netscape 6; Netscape only included innerHTML support to appease the overwhelming demand for it. To change content effectively with W3C compliance, we could create each little element, append text to it, etc.... For example, to put the following HTML code in another element, we'd have to do a lot of work. Here's the HTML code we want to insert:
This is <b>some bolded</b> text.
And to create that, we'd have to use:
text1 = document.createTextNode("This is ");
bTag = document.createElement("b");
textB = document.createTextNode("some bolded");
text2 = document.createTextNode(" text.");
bTag.appendChild(textB);
document.body.appendChild(text1);
document.body.appendChild(bTag);
document.body.appendChild(text2);
Wow, that sure was a lot of work for such a simple thing, which we could have just done:
document.body.innerHTML="This is <b>some bolded</b> text.";
As you can see, creating each little element can be very can become tedious and time-consuming. This is one reason why ranges are needed. A range is an area (or range) of any HTML (or XML) content. It can span across multiple tags, in between text nodes, etc.... This is major enhancement in Level 2. You can again hear about this from the "horse's mouth" in somewhat technical discussions at Document Object Model Core and Document Object Model Range, and there's a good article on ranges by Jeffrey Yates, which I recommend you read. Although we won't discuss the details of ranges as that could be a long discussion (the article by Jeffrey Yates, link above, explains about ranges), we will use it to change a layer's content. Here's the proper means of changing a layer's content (works in NS 6 but not IE 5) by W3C DOM Standard using ranges. Consider this function:
function writeLayerNSSix(node,txtHTML){
var newRange = document.createRange();
newRange.selectNodeContents(node);
newRange.deleteContents();
var newHTML = newRange.createContextualFragment(txtHTML);
node.appendChild(newHTML);
}
Let's apply it to replace the text in "span1":
<div id="div1">
<span id="span1">This is the text of SPAN1</span>
This text is not in a span tag.
</div>
<script>
writeLayerNSSix(document.getElementById("span1"),"Now, this is the <b>NEW</b> text for <i>SPAN1</i><b>!</b>");
</script>
Our document now looks like:
<div id="div1">
<span id="span1">Now, this is the <b>NEW</b> text for <i>SPAN1</i><b>!</b></span>
This text is not in a span tag.
</div>
Recreate our generic writeLayer() function.
I should also note the function we created to change a layer's content (way back when we used innerHTML) is not W3C compliant, even though it does work in NS 6. To make it W3C compliant, our code is going to be a little longer. However, before we begin, we must learn a way to distinguish between browsers IE 5 and NS 6. We could use if(document.getElementById&&!document.all) and that will work, but what about IE 6? IE 6 supports document.all, and it will return false for that statement and keep on using the older "innerHTML method," when it could use the W3C compatible way, like NS 6. So, since IE 5 and IE 5.5 don't support getAttributeNode() (which we haven't discussed in this article, but you can find more information about it from W3C) for elements, we can use if(document.body.getAttributeNode), knowing the NS 6 and IE 6 support that feature and will return true for that while IE 5 and other browsers will return false for that if() statement. In light of this,
let's rewrite our function to change a layer's content:
function writeLayer(layerID,txt){
if(document.body.getAttributeNode){
node = document.getElementById(layerID);
var newRange = document.createRange();
newRange.selectNodeContents(node);
newRange.deleteContents();
var newHTML = newRange.createContextualFragment(txtHTML);
node.appendChild(newHTML);
}else if(document.getElementById){
document.getElementById(layerID).innerHTML=txt;
}else if(document.all){
document.all[layerID].innerHTML=txt;
}else if(document.layers){
with(document.layers[layerID].document){
open();
write(txt);
close();
}
}
}
Notice that we just pass the layerID, rather than the node. This is added for compliance, and I also added this line which was not included in our writeLayerNSSix() function to accomplish this:
node = document.getElementById(layerID);
Events are used to perform an action in response to a user's action. Most of you are familiar with a simple example:
<a href="javascript:void(0)" id="link1" onMouseOver="alert('Hey, get off of me')">Don't come near me</a>
In response to the user mousing over the link, we get an alert() message. This is basic event handling. To get a little more advanced, let's look at advanced event handling in Internet Explorer 5 before we move on to event handling in W3C DOM Level 2.
Internet Explorer 5
In IE 5, you can also attach events to nodes with the attachEvent() method. It takes two arguments, the event to be processed, and what function will occur on this event. To show you an example of this, let's take a look at this script:
<a href="javascript:void(0)" id="link1">Don't come near me</a>
<script>
function alertMessage(){
alert('Hey, get off of me');
}
document.getElementById("link1").attachEvent("onmouseover", alertMessage);
</script>
Note that I used "onmouseover." It won't work if I use "onMouseOver," or anything else...it must be in all lowercase. Also note that when I called for the function, alertMessage(), I omitted the parenthesis.
W3C DOM Level 2 Events
Now that you have an idea of how this works, let's examine W3C DOM Level 2 events. The full technical document on this can be found on the W3C site here: Document Object Model Events
Capture or Bubble?
Remember how DOM is just a hierarchal structure of nodes on the page? Well, when an event goes off in one of those nodes, the event has three choices:
- The event can occur in the node and only set off the event handler for that node.
- The event can occur in the node, set off the event handler for it's top ancestor, and continue down the hierarchal structure, setting of the event handler for each node as it goes through it until it sets off the event handler for the node that the event occurred in.
- The event can occur in the node, set off the event handler for that node, and propagate upwards through the hierarchal structure until it reaches the very top ancestor.
Let's take a look at an example page:
<html>
<head>
</head>
<body>
<div id="div1">
<span id="span1">
Click Me
</span>
</div>
</body>
</html>
And now, let's look at a diagram of the three ways an event can dispatch in this document:
1. Event applies to only that node in which the event occurs in
2. Capturing - when an event occurs in a node and fires the event starting from the top ancestor to the node the event occurred in.
3. Bubbling - when an event occurs in a node and fires the event starting from the node the event occurred in, propagating all the way up to the top.
Understanding the Methods
Now that we see and understand the three main ways an event can occur, let's look at some coding.
addEventListener(eventType, Function, useCapture) adds an event listener to the node it is "run from."
- The first argument accepts what type of event to detect. Note that you leave out the all-familiar "on." So instead of using "onclick," you use "click" (all lowercase).
- The second argument accepts the function to occur on the event. We'll look at how to pass this in more detail in our examples.
- The last argument accepts a Boolean value of true or false. If it is set to true, the event captures, meaning that the event first goes off in the top ancestor and then moves downward towards this node. If it is set to false, the event bubbles, meaning that the event first goes off in the node and propagates upward to its top ancestor.
removeEventListener(eventType, Function, useCapture) removes an event listener from the node it is "run from." Note that all the arguments must be exactly the same as how you set it with the addEventListener() method. So, if you set the useCapture argument to false when you set the event listener with the addEventListener() method and try to remove it with the removeEventListener() method with the useCapture argument set to true, it won't work.
stopPropagation() stops the event from traversing the rest of the document (it stops the event in its hierarchal tracks). For example, it would stop the event from capturing and going down to the events origins, and it would stop the event from bubbling and going up to its top ancestor.
Examples
Capturing Example - Click on the text node and watch how it alerts first the "#document" and goes all the way down to the text node. Also, look at the code and how the addEventListener() method works.
Bubbling Example - Click on the text node and watch how it alerts "#text" first and then propagates itself upward through the hierarchal structure.
stopPropagation Example - Click on the text node and watch it propagate upwards to the span1(<span> tag) node. Then, the div1(<div> tag) calls the stopPropagate() method, which then stops the event from bubbling up any further.
Now that we've finally finished covering events, let's look at an in-depth DOM example.
Kaynak www.pageresource.com/dhtml/ryan/part4-3.html