Help with using the dom to create a new link element and inserting it...

H

hgraham

Hi,

I'm trying to understand how to work the dom, and all I'm trying to do
is insert a link right before another link in the html based on it's
href value. This isn't a real world example - I'm just trying to do
this in phases to understand what's going on. I'm getting an error
(Object doesn't support this property or method) in IE and I can't
figure out what I'm doing wrong. Can anyone tell me?

if (navigator.appName == "Microsoft Internet Explorer")
{
var browser="IE";
}
else
{
var browser="notIE";
}
var e = document.getElementById('contentWrapper');
if (e)
{
var a=e.getElementsByTagName('a');
for (var i=0;i<a.length;i++)
{
if (browser == "IE")
{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)
{
var iconLink = e.createElement('a');
iconLink.href = a.href;
iconLink.title = 'This link takes you to another web site.';
iconLink.appendChild(e.createTextNode('Test'));
a.title = 'This link takes you to another web site.';
a.parentNode.insertBefore(iconLink,a);
}
}
else....

Thanks!
Holli
 
H

hgraham

Well, I figured out that I have to change the e to document on this
line:

var iconLink = e.createElement('a'); change to
var iconLink = document.createElement('a');

Now, IE just freezes. Now what? I'm guessing this will be an easy
answer for someone.

Thanks!
Holli
 
A

ASM

(e-mail address removed) a écrit :
Hi,

I'm trying to understand how to work the dom, and all I'm trying to do
is insert a link right before another link in the html based on it's
href value. This isn't a real world example - I'm just trying to do
this in phases to understand what's going on. I'm getting an error
(Object doesn't support this property or method) in IE and I can't
figure out what I'm doing wrong. Can anyone tell me?

if (navigator.appName == "Microsoft Internet Explorer")

var IE = false; /*@cc_on IE = true; @*/
{
var browser="IE";
}
else
{
var browser="notIE";
}
var e = document.getElementById('contentWrapper');
if (e)
{
var a=e.getElementsByTagName('a');
for (var i=0;i<a.length;i++)
{
if (browser == "IE")
if(IE)
{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)


var lk = a.href;
if( lk && lk.indexOf('://')>0 && lk.indexOf('bcbsal.org')<0)ment('a');
{
var iconLink = document.createElement('A');
iconLink.href = lk;
iconLink.title = 'This link takes you to another web site.';
iconLink.innerHTML = 'Test';
/*
or
iconLink.firstChild.nodeValue = 'Test';
or
var tx = document.createTextNode('Test');
inconLink.appendChild(tx);
*/
a.title = 'This link takes you to another web site.';
a.parentNode.insertBefore(iconLink,a);
}
}
}
 
R

RobG

Hi,

I'm trying to understand how to work the dom, and all I'm trying to do
is insert a link right before another link in the html based on it's
href value. This isn't a real world example - I'm just trying to do
this in phases to understand what's going on. I'm getting an error
(Object doesn't support this property or method) in IE and I can't
figure out what I'm doing wrong. Can anyone tell me?

Don't use tabs for indents in posted code, use 2 (preferred) or 4
spaces. Manually wrap code at about 70 characters to prevent
auto-wrapping, otherwise errors may be introduced there weren't in the
original code.

if (navigator.appName == "Microsoft Internet Explorer")

Ditch that straight away, browser sniffing has been out of vogue for
many years, feature detection is all the rage.

{
var browser="IE";
}
else
{
var browser="notIE";
}
var e = document.getElementById('contentWrapper');

It is much better to give your variables meaningful names, single
letters are OK for counters and such, your choice.

var wrapper;
if (document.getElementById){
wrapper = document.getElementById('contentWrapper');


Good, you check that getElementById returned something. :)

{
var a=e.getElementsByTagName('a');

'a' is now a collection of the 'A' elements that are decedents of
'contentWrapper'. A feature of such collections is that they are live -
as you add A elements to contentWrapper in your code below, they are
also added to the collection.

This has ramifications for your loop below - the length keeps getting
longer and because you insertBefore the current node, it will keep
inserting forever once the if condition is true.

for (var i=0;i<a.length;i++)

It is more efficient (though often not noticeably so) to get the length
of the collection once only. Getting the length every time in this case
will cause you go to into an endless loop because you keep inserting
nodes before the current one - better to loop from the end back to the
start using while, then the inserted nodes are beyond where you are
currently checking:

var i = a.length;
while (i--){

{
if (browser == "IE")

Ditch that.

{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)


It is easier to access properties directly, though it's not standard it
is better supported than get/setAttribute. It is also better to get a
reference to the element once and use that rather than lookup a
multiple times:

var i = a.length;
while (i--){
tmp = a;

indexOf is pretty efficient, but rather than doing all those tests you
might consider using a regular expression and just the one test:

if ( /bcbsal\.org/.test(temp.href) )


The above will return false if either the element doesn't have a value
for the href attribute or it doesn't match "bcbsal.org". You might want
to also make the test case insensitive:

if ( /bcbsal\.org/i.test(temp.href) )

{
var iconLink = e.createElement('a');

This is the line that is causing your error: 'e' is a reference to an
element, elements implement the HTML element interface which doesn't
have a createElement() method, that belongs to the HTML document
interface so you have to call it with 'document':

var iconLink = document.createElement('a');

Some links:

DOM 2 Core Document Interface:
<URL:http://www.w3.org/TR/DOM-Level-2-Core/core.html#i-Document>

DOM 2 Core Element Interface:
<URL:http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-745549614>

There are further interfaces defined in the DOM 2 HTML spec:
iconLink.href = a.href;


The problem here is that you insert an A element before a node, which
makes the node the i+1 node in the collection, so the next loop tests
the same node, matches the href, inserts another link, moves the node +1
again, etc. /ad infinitum/.

iconLink.title = 'This link takes you to another web site.';
iconLink.appendChild(e.createTextNode('Test'));

Again, createTextNode is a method of document, not element:

iconLink.appendChild(document.createTextNode('Test'));

a.title = 'This link takes you to another web site.';
a.parentNode.insertBefore(iconLink,a);
}
}
else....



Putting it all together:

<div id="contentWrapper"><br>
<a href="http://www.bcbsal.org">bcbsal.org</a><br>
<a href="http://www.apple.com">Apple a</a><br>
<a href="">Empty a</a><br>
</div>

<script type="text/javascript">

if (document.getElementById){
var wrapper = document.getElementById('contentWrapper');

if (wrapper){
var a = wrapper.getElementsByTagName('a');
var tmp;
var iconLink;
var i = a.length;

while (i--){
tmp = a;

if ( /bcbsal\.org/.test(tmp.href) ){
iconLink = document.createElement('a');
iconLink.href = tmp.href;
iconLink.title = 'This link takes you to another web site.';
iconLink.appendChild(document.createTextNode('Test'));
tmp.title = 'This link takes you to another web site.';
tmp.parentNode.insertBefore(iconLink,tmp);
}
}
}
}

</script>
 
R

RobG

RobG wrote:
[...]
It is more efficient (though often not noticeably so) to get the length
of the collection once only. Getting the length every time in this case
will cause you go to into an endless loop because you keep inserting
nodes before the current one - better to loop from the end back to the
start using while, then the inserted nodes are beyond where you are
currently checking:

var i = a.length;
while (i--){

Another solution is to increment i a second time if the test is true,
but that may be bad for maintenance (then again, the reason for the
while loop may not be understood either...):

for (var i=0, len=a.length; i<len; i++){
if (...){
// insert element before current element
// increment i to account for inserted element
i++;
}
}
 
R

Randy Webb

RobG said the following on 5/11/2006 9:54 PM:
RobG wrote:
[...]
It is more efficient (though often not noticeably so) to get the
length of the collection once only. Getting the length every time in
this case will cause you go to into an endless loop because you keep
inserting nodes before the current one - better to loop from the end
back to the start using while, then the inserted nodes are beyond
where you are currently checking:

var i = a.length;
while (i--){

Another solution is to increment i a second time if the test is true,
but that may be bad for maintenance (then again, the reason for the
while loop may not be understood either...):

Depending on what the intentions are. If you want to go through the
entire collection, then use the while. If you want to only do the first
one you find, then you can break; out of the for loop. That will keep
from going through a long collection to do only the first one.
for (var i=0, len=a.length; i<len; i++){


var len = a.length;
for (var i=0;i<len;i++)

Never cared for the len definition in the for loop :)
if (...){
// insert element before current element
// increment i to account for inserted element
i++;

break;
// :)
 
A

ASM

RobG a écrit :
This has ramifications for your loop below - the length keeps getting
longer and because you insertBefore the current node, it will keep
inserting forever once the if condition is true.

Too much !
I thought a.length was seen once.

I now understand better :

for(var i=0, len=a.length; i<len; i++)
 
R

Richard Cornford

RobG said:
(e-mail address removed) wrote:
{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)


It is easier to access properties directly, though it's not
standard it is better supported than get/setAttribute. ...

<snip>

Not standard? Doesn't the W3C HTML DOM define a - href - property on the
HTMLAnchorElement interface? Is there something that is more 'standard'
than the W3C DOM?

Richard.
 
R

Richard Cornford

ASM said:
(e-mail address removed) a écrit :

var IE = false; /*@cc_on IE = true; @*/

But what is it about this script that would require an interest in
whether the browser is IE or not?

a.getAttribute('href',2).indexOf("bcbsal.org") == -1)


var lk = a.href;
if( lk && lk.indexOf('://')>0 && lk.indexOf('bcbsal.org')<0)ment('a');

<snip> ^^^^^^^^^

You might want to correct that line as it radically alters the behaviour
of the following code.

Richard.
 
R

RobG

Richard said:
RobG said:
(e-mail address removed) wrote:
{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)

It is easier to access properties directly, though it's not
standard it is better supported than get/setAttribute. ...

<snip>

Not standard? Doesn't the W3C HTML DOM define a - href - property on the
HTMLAnchorElement interface? Is there something that is more 'standard'
than the W3C DOM?


The W3C Core specification has getAttribute and setAttribute, I figured
they are the 'standard' ways to get/set properties of DOM objects.
 
I

Ian Collins

RobG said:
Richard said:
RobG said:
(e-mail address removed) wrote:

{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)

It is easier to access properties directly, though it's not
standard it is better supported than get/setAttribute. ...


<snip>

Not standard? Doesn't the W3C HTML DOM define a - href - property on the
HTMLAnchorElement interface? Is there something that is more 'standard'
than the W3C DOM?



The W3C Core specification has getAttribute and setAttribute, I figured
they are the 'standard' ways to get/set properties of DOM objects.

They are, but there is also "Document Object Model (DOM) Level 2 HTML
Specification" which expands the core DOM for HTML.
 
R

RobG

Ian said:
RobG said:
Richard said:
RobG wrote:

(e-mail address removed) wrote:
<snip>

{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)
It is easier to access properties directly, though it's not
standard it is better supported than get/setAttribute. ...
<snip>

Not standard? Doesn't the W3C HTML DOM define a - href - property on the
HTMLAnchorElement interface? Is there something that is more 'standard'
than the W3C DOM?


The W3C Core specification has getAttribute and setAttribute, I figured
they are the 'standard' ways to get/set properties of DOM objects.

They are, but there is also "Document Object Model (DOM) Level 2 HTML
Specification" which expands the core DOM for HTML.


Yes, I included a reference to that in my response to the OP. The DOM
HTML spec details interfaces and properties for HTML elements, but in
terms of get/set-ting attributes, that is in the Core spec.

Of course, it's fair that programmers take advantage of language
features like 'dot' property accessors and it's probably not suitable to
say they're "not standard" in response to a general question (as I did
in my original response).

I was just trying to point out in my response to Richard that, strictly
speaking, it is a standard feature of the JavaScript language, not of
the W3C DOM.
 
I

Ian Collins

RobG said:
Ian said:
RobG said:
Richard Cornford wrote:

RobG wrote:

(e-mail address removed) wrote:

<snip>

{
if (a.getAttribute('href') != null &&
a.getAttribute('href',2).indexOf("://") >= 0 &&
a.getAttribute('href',2).indexOf("bcbsal.org") == -1)

It is easier to access properties directly, though it's not
standard it is better supported than get/setAttribute. ...

<snip>

Not standard? Doesn't the W3C HTML DOM define a - href - property on
the
HTMLAnchorElement interface? Is there something that is more 'standard'
than the W3C DOM?


The W3C Core specification has getAttribute and setAttribute, I figured
they are the 'standard' ways to get/set properties of DOM objects.

They are, but there is also "Document Object Model (DOM) Level 2 HTML
Specification" which expands the core DOM for HTML.



Yes, I included a reference to that in my response to the OP. The DOM
HTML spec details interfaces and properties for HTML elements, but in
terms of get/set-ting attributes, that is in the Core spec.

Oops, didn't spot that at the end.
Of course, it's fair that programmers take advantage of language
features like 'dot' property accessors and it's probably not suitable to
say they're "not standard" in response to a general question (as I did
in my original response).

I was just trying to point out in my response to Richard that, strictly
speaking, it is a standard feature of the JavaScript language, not of
the W3C DOM.
Which makes it a shame that it's somewhat broken in IE.

Cheers,
 
R

Richard Cornford

Standard ways of setting _attributes_ on DOM Elements. Attributes being
(in this context) objects implementing the W3C Core DOM - Attr -
interface.
Yes, I included a reference to that in my response to the OP. The DOM
HTML spec details interfaces and properties for HTML elements, but in
terms of get/set-ting attributes, that is in the Core spec.

Of course, it's fair that programmers take advantage of language
features like 'dot' property accessors and it's probably not suitable to
say they're "not standard" in response to a general question (as I did
in my original response).

I was just trying to point out in my response to Richard that, strictly
speaking, it is a standard feature of the JavaScript language, not of
the W3C DOM.

The HTMLAnchorElement interface is defined in the W3C HTML DOM standard
as having an - href - property. That is not a feature of javascript as
javascript (ECMAScript) has no business defining properties of host
objects and it is host objects that are implementing HTMLAnchorElement.

Richard.
 
A

ASM

Richard Cornford a écrit :
But what is it about this script that would require an interest in
whether the browser is IE or not?

I don't know the interest of OP, it was not my purpose.
It is only an alternative to his request "is it IE ?"
I think much more clean (hope Opera doesn't understand it)

Answer about how to really do was given in some other post(s)
<snip> ^^^^^^^^^

You might want to correct that line as it radically alters the behaviour
of the following code.

Oooops !
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top