PDA

View Full Version : to loop or not to loop?



Falkon303
07-08-2009, 10:25 PM
Let's say I have the following HTML -


<form id="form1" name="form1">
<ul id="mn" name="mn">
<li id="one" name="one">bleh</li>
<li id="blarg" name="blarg">bluh</li>
<li id="goats" name="goats">blah</li>
</ul>
</form>


Normally, there would be a loop function to gather all of the elements within the "mn" ul element. I am curious if there is an alternative to looping that will provide me with an array of the li elements.

vwphillips
07-09-2009, 08:48 AM
var lis=document.getElementById(mn).getElementsByTagName('LI');

is a 'collection' which is similar to an array.

Falkon303
07-09-2009, 05:22 PM
Thanx much for the response. So in theory, this would be more efficient than looping through elements? I considered not using the "onload", but rather putting that in the javascript, but this is a much more useful way to retrieve elements in my opinion. Thanx for the help VW.

Perhaps I'll do a time test on this in comparison to another method to see exactly what's going on.

I'd love to hear more thoughts on this.



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Element Collection</title>
<script type="text/javascript">
function retel()
{
count = document.getElementById('mn').getElementsByTagName('LI').length;
for (i=0;i<=count-1;i++)
{
alert((i + 1) + ' of ' + count + ' Elements Found -> id:' + document.getElementById('mn').getElementsByTagName('LI')[i].id + ' -> Text:' + document.getElementById('mn').getElementsByTagName('LI')[i].firstChild.nodeValue);
}
}
</script>
</head>
<body onload="retel();">
<form id="form1" name="form1">
<ul id="mn" name="mn">
<li id="newid1" name="newid1">new1</li>
<li id="newid2" name="newid2">new2</li>
<li id="newid3" name="newid3">new3</li>
<li id="newid4" name="newid4">new4</li>
<li id="newid5" name="newid5">new5</li>
<li id="newid6" name="newid6">new6</li>
<li id="newid7" name="newid7">new7</li>
<li id="newid8" name="newid8">new8</li>
</ul>
</form>
</body>
</html>

Trinithis
07-09-2009, 07:30 PM
I wouldn't worry about efficiency for a function that (more than likely) runs in linear or constant time. That aside, the built-in browser version should be faster.

To convert into an array, you could do:


var lis = Array.prototype.slice.call (document.getElementById (mn).getElementsByTagName ('li'));

I may be mistaken, but the above code might give IE issues. In that case, if you need it as an array, you could always use something like this:


function toArray (xs) {
var ys = [];
for (var i = 0; i < xs.length; ++i) {
ys [i] = xs [i];
}
return ys;
}

Jesdisciple
07-10-2009, 03:22 AM
If you know that you want all children, you could even skip the looping and just get ul.childNodes.

Falkon303
07-10-2009, 05:03 PM
If you know that you want all children, you could even skip the looping and just get ul.childNodes.

Thanks for this. I am very interested. Could you please explain a bit more in depth or possibly give an example?

Thanx much,

- Ben

Jesdisciple
07-10-2009, 05:33 PM
The DOM (Document Object Model) keeps track of all children of every node in an array-like object called childNodes (http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1451460987). Just access this property on any node to get that node's children.
The DOM Level 1 Node interface also defines the childNodes attribute, which is a live list of all child nodes of the node; the childNodes list has a length attribute to expose the total number of child nodes of all nodeTypes, useful for preprocessing operations and calculations before, or instead of, looping through the child nodes.EDIT: Note that grandchildren are not included in this list.

Falkon303
07-10-2009, 08:28 PM
Thanx much for the response.

What I trying to accomplish is a DOM returned array string of node ids without having to use a looping function as posted earlier.

I'll try and explain it here ---

Now, running the script below, you'll see it returns the array length, and the id property of node #2, yet I can't help but wonder if there is such a usage as -

document.getElementById('ul').childNodes.toArray().join("");

Anything similar?



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>nodes</title>
<script type="text/javascript">
function get()
{alert('How many LI Elements? : ' + document.getElementById('ul').childNodes.length);
alert('LI Elements #2 id? : ' + document.getElementById('ul').childNodes[1].id);}
</script>
</head>
<body onload="get();">
<ul id="ul" name="ul">
<li id="1" name="1">one</li>
<li id="2" name="2">two</li>
<li id="3" name="3">three</li>
<li id="4" name="4">four</li>
</ul>
</body>
</html>

Jesdisciple
07-10-2009, 09:23 PM
Oh, you want the IDs? No, there's no way to skip the loop for that. I thought you just wanted the elements.

I am curious though why you're afraid of loops.

Falkon303
07-10-2009, 11:54 PM
Oh, you want the IDs? No, there's no way to skip the loop for that. I thought you just wanted the elements.

I am curious though why you're afraid of loops.

I am not afraid of loops, but rather curious of some of the more obscured javascript functionality, such as using "nodeList.nextSibling" (as seen at - http://www.irt.org/xref/ie_5.htm ), or something similar to somehow increment through the elements.

I am unsure how to use "nextSibling", but in some of the examples, it proceeds to the next element. Perhaps using "nextSibling.id" or something similar would work. Of course then we have to use a loop depending on the nodelength, so maybe there must always be a loop....

Just curious if it can be done.

hrm.

Jesdisciple
07-11-2009, 12:46 AM
What examples? I don't see very much useful information at that site - just names of properties and methods.

Anyway, nextSibling still requires a loop, just a different kind:
var element = defineIt;
var ids = [];
while(element != null){
ids.push(element.id);
element = element.nextSibling;
}

Falkon303
07-11-2009, 07:40 PM
I apologize for the weak link. I think I was making examples up in my head.


What examples? I don't see very much useful information at that site - just names of properties and methods.

Anyway, nextSibling still requires a loop, just a different kind:
var element = defineIt;
var ids = [];
while(element != null){
ids.push(element.id);
element = element.nextSibling;
}

Thanx for the response. This actually kind of answers my question perfectly.

So on one hand, you can assign "i", a value of 0, and telling the loop "while x is larger than i, do what is in these brackets.", so essentially, the loop has to remember what "i" is by loading it into memory, load what "x" is into memory, and then also do a mathematical comparison via x-y =.

On the other hand, you are using a while loop, you are finding an element via DOM, pushing it as the "nextsibling", and then checking an element, and if the element has a value, a function is performed, and if not, it stops.

Yet there is no way to retrieve an array of their ids, yet you can retrieve a ".length" value that can be used to form a loop. Trinithis posted a way to use a built in browser version, but then you have to factor in browser compatibility checking, which I try and avoid if possible...this is good stuff to know. I wonder why there you can retrieve "childNodes.length', but not something like "childNodes.nodeValues.ids", or some array of the ids. It just seemed odd it could count the elements incrementally, but not their unique properties as arrays if needed.

What I am getting at, is knowing which method (you found exactly what I was looking for) is more efficient. It may seem inconsequential, but I think it's kind of good to know the most efficient way to do things like retrieving arrays.

I have no way of knowing myself unless I find a memory usage/runtime script, but this interested me a lot was all. Thanks much for the insight. :)

Jesdisciple
07-11-2009, 08:48 PM
I think an array of every type of element property on every NodeList or HTMLCollection would take up more memory than it would save...

Also, the while loop can be rewritten as a for loop:
function getProperties(parent, property){
var properties = [];
for(var e = parent.firstChild; e != null; e = e.nextSibling)
properties.push(e[property]);
return properties;
}EDIT: I added the second parameter to get the closest I could to what you wanted:
var ids = getProperties(element, 'id');
EDIT: Oh, also... I have a mostly incomplete reference wiki that I'm building up according to properties and methods people ask about. Here's the Node page (http://javascript.wikia.com/wiki/Node). (You can edit it if you like.)