...

View Full Version : Links Collection



Honza
11-11-2004, 01:07 PM
Hi!

Every link on a page is a member of links collection and has its unique number (index) from 0 to document.links.width. Well.
But can I get that index directly for link being clicked without looping through all links members and comparing against clicked link.

Thank you
Honza

adios
11-11-2004, 07:07 PM
Assume you have a reason for this. :) You're basically going to loop one way or another, afaik, so, might as well do it up front.




<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<title>untitled</title>
<style type="text/css">

a { display: block; }

</style>
<script type="text/javascript">

function initLinks()
{
var link, idx = 0;
while (link = document.links[idx])
link.idx = idx++;
}

onload = initLinks;

</script>
</head>
<body>

<a href="#null" onclick="alert(this.idx)">This is link 0.</a>
<a href="#null" onclick="alert(this.idx)">This is link 1.</a>
<a href="#null" onclick="alert(this.idx)">This is link 2.</a>
<a href="#null" onclick="alert(this.idx)">This is link 3.</a>
<a href="#null" onclick="alert(this.idx)">This is link 4.</a>

</body>
</html>


Don't necessarily need to wait till the page is loaded, probably better to embed the script below all the links (and 'de-functionize' it).

Honza
11-13-2004, 10:17 PM
Hi adios,

Your code is very inspiriting, elegant (also very hard to understand) and I thank you very much.
The reason for my question is simple. I use one menu across some website. So I need to remember (in cookie) which link (in menu) was clicked and later (on "subpage") highlight this link as current by means of simple command like


document.links[ClickedLink].style.blahblah="somevalue"

By the way: yesterday I discovered some other solution without cookies. I need not to remember clicked link any more and only on a new page I loop through all links in menu looking for coincidence with URL of that page


//code fragment...
if (document.getElementsByTagName("A")[i]== location.href)
{
// this link correspondents to current page so highlight it
document.links[i].style.backgroundColor="#FFFFFF"
}

This is quite new I think.
Honza

adios
11-15-2004, 12:08 AM
Thanks for the compliment (I think!). afaik the only difference between using the DOM 0 host collection document.links[] and the document.getElementsByTagName('A') method is that the latter will collect page anchors as well as links, and the collection isn't guaranteed to be in the same order as the HTML source (although I can't recall ever seeing it ordered differently). I'd use one or the other....




onload = function()
{
var url = self.location.href,
i = 0,
link;
while (link = document.getElementsByTagName('A')[i++])
if (link.href && url.search(link.href) != -1)
link.style.background = '#ffffff';
}

Honza
11-16-2004, 03:42 PM
Hi adios,
Your JavaScript teacher had to be a great man. Congratulations.
It took me three days to fully understand your


var link, idx = 0;
while (link = document.links[idx])
link.idx = idx++;
...

At least I find that there is single "=" in condition. Does it mean that condition for entering "While" is true if assigning "document.links[idx]" to variable "link" is successful (e.g. document.links[idx] exists)? Am I right?
By the way your code for (to me) unknown reasons - can't be debugged using some Alert.
Will you kindly give me a little explanation?
Thank you
Honza

liorean
11-16-2004, 05:29 PM
Honza: No, it doesn't mean that. Assignments can only fail if the property or variable you are assigning to is read only, which is a very rare event indeed. And anyway, when that occurs an exception will be thrown. No, it will perform the assignment, and then the while will cast whatever condition it is given to boolean, and determine whether it should continue depending on that.

adios
11-16-2004, 07:02 PM
This:



while (link = document.links[idx])
link.idx = idx++;



...is simply a 'compressed' version of this:



while (document.links[idx])
{
link = document.links[idx];
link.idx = idx;
idx++;
}


Just 1) doing an assignment, for efficiency/convenience, 2) evaluating a conditional for the while loop (Object == true), 3) assigning a new property - the one with the data you requested (probably should have named it 'index'), and 4) bumping up the counter. The assignment tends to confuse people, who expect a comparison (==) with two operands present, but the interpreter performs the assignment, and then evaluates the right-hand operand solely (not much point in doing both). That's my (un)educated guess, in any event. This is a bit more compressed:



while (link = document.getElementsByTagName('A')[i++])


...as it post-increments the counter in the same line. Lately (inspired in part by liorean) I've been jamming more and more expressions into each line of code. My goal is to make it completely unreadable so people will be impressed. Seems to be working with you. :thumbsup:

Would need to see an example of that debug dilemma.

cya, adios

liorean
11-16-2004, 07:43 PM
A thing to note:
var
elm,
col=document.getElementsByTagName('a'),
i=0;
while(elm=col.item(i++))
doSomethingWith(elm);is the absolutely most effective way to circle through a DOM collection there is.

The shortcut way that adios used, which could be summarised as
while(elm=col[i++])is NOT recommended, since it at the end would try accessing an element that does not exist and consequently raise an exception instead of nicely returning null when the index does not contain a an element. The exception breaks execution, but the null is cast to false. and thus allows further execution.









Adios: Jamming more and more expressions into one line of code is not a good rule of thumb. Keep code readable and keep your personal coding conventions consistent. However, it is a good idea to reduce the number of statements and expressions altogether in your code, and one of the best ways to do that is to inline expressions in other expressions where that can be done. That doesn't mean it's a good idea to jam the entire expression or statement into one single line, however. Consider this example
document
.getElementsByTagName('head')
.item(0)
.appendChild(
script=document.createElement('script'));

// or

document
.getElementsByTagName('head').item(0)
.appendChild(script=document.createElement('script'));

// or

document.getElementsByTagName('head').item(0)
.appendChild(script=document.createElement('script'));

// or

document.getElementsByTagName('head').item(0).appendChild(
script=document.createElement('script'));

// or

document.getElementsByTagName('head').item(0).appendChild(script=document.createElement('script'));
Now, that is a single expression. It looks nice as a five-liner. It looks pretty nice as a three-liner as well. The first two-liner is okay, but the second one is clumsy. The one-liner is bad coding.

adios
11-16-2004, 08:30 PM
Hi David. Always look forward to your assessments. Think you took my comments a bit too literally, particularly in re that 'one line' business. I was thinking of this monster:




Number.prototype.toOrdinal=function(m){
return (this +
["th","st","nd","rd"][(!(
((m=this%10) >3) ||
(Math.floor(this%100/10)==1)
))*m]);
}


...whose multi-line formatting mitigates none of its fabulous algorithmic density. But you've heard that a million times by now.

Interesting:
The shortcut way that adios used, which could be summarised as while(elm=col[i++]) is NOT recommended... What's interesting is that I've always done it the way you illustrated, encapsulating the looping in the .item() method, until recently I was 'corrected' by someone, who cited PPK (http://www.quirksmode.org/dom/w3c_core.html) (scroll to bottom), a source I generally trust. Maybe you could explain why some (JS) out-of-bounds situations seem to throw exceptions and others seem to fail gracefully...or is that just my imagination?

liorean
11-17-2004, 03:05 PM
Hi David. Always look forward to your assessments. Think you took my comments a bit too literally, particularly in re that 'one line' business.Well, I CHOSe to do that interpretation, since it would give me an excuse to write an explanation why that interpretation was a bad one for those other readers of this thread that would do that interpretation.
I was thinking of this monster:
Number.prototype.toOrdinal=function(m){
return (this +
["th","st","nd","rd"][(!(
((m=this%10) >3) ||
(Math.floor(this%100/10)==1)
))*m]);
}...whose multi-line formatting mitigates none of its fabulous algorithmic density. But you've heard that a million times by now.I think I did a quite good job at the formatting of that considering it's highly mathematical nature... Of course, some code is harder to make nice and readable than other code.
Interesting: What's interesting is that I've always done it the way you illustrated, encapsulating the looping in the .item() method, until recently I was 'corrected' by someone, who cited PPK (http://www.quirksmode.org/dom/w3c_core.html) (scroll to bottom), a source I generally trust.That is something I wouldn't do. From my experience PPK is heavily biased towards the way he's always been doing things and the "it works, it must be right", he doesn't consult the documentation and specifications before he draws his conclusions, he's hasty at making assumptions that are in no way given, and he doesn't listen very much to others. His tables are based on tests, and those test results I generally trust (but not blindly). But never trust his conclusions until you have tested that they are accurate as well.

jkd
11-17-2004, 05:04 PM
I'd venture on those examples that, regardless of format, sticking the variable assignment outside of it is much nicer:



var script = document
.getElementsByTagName("head").item(0)
.appendChild(document.createElement("script"));


Than assigning to the variable inside the appendChild. It's just sloppy really.

adios
11-17-2004, 06:03 PM
If the two of you would like to duke it out over this (http://www.codingforums.com/showthread.php?t=18442) I'd enjoy reading that.

Also: what ever happened to 'JavaScript strict warnings'? I thought they were set to derail habits like object detection without the typeof operator, but it doesn't seem to have happened.

Agree on PPK, his site in itself is a nightmare to navigate. Doesn't bode well for his accuracy.

liorean
11-17-2004, 09:31 PM
Jason: Of course, you're right about that...

Adios: Well, the DOM guarantees that all elements of a collection are nodes, and that collections are compact. That means that we know that the only time iterating over a collection and getting a value that typecasts to false is when we hit the end of the collection. That means that the while and item(i++) method of doing it is guaranteed by the specs to work in any single threaded language. It also has the benefits of both being clean coding and being the absolutely fastest method of iterating over a collection devised so far.

adios
11-18-2004, 05:24 AM
And the debate (http://www.codingforums.com/showthread.php?t=16839&page=1&pp=15) continues.... ;)

OK, how 'bout...



var
elm,
col=document.getElementsByTagName('a'),
i=col.length;
if (i)
do
{
elm=col[--i];
doSomethingWith(elm);
}
while (i);


As noted here (http://www.webreference.com/programming/optimize/speedup/chap10/3/2.html), 'downwards' iteration is more efficient ('Flipped Loop with Reversed Count' et al).

codegoboom
11-20-2004, 05:46 AM
To me, it looks to be browser dependent. The really odd thing is that the optimal loop for Moz is the one and only construct that saps the heck out of IE (which is usually twice as fast with anything other than liorean's example).



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum