Help - Search - Member List - Calendar
Full Version: getElementById problem with Firefox
WorkTheWeb Forums > Webmaster Resources > JavaScript Help
Support our Sponsors!
Robi
I have the following problem:
I populate a page with a specific amount of <div id="MyTest"> containers inside another <div> container.

for (i=0; i < MyString.length; i++)
document.write('<div id="MyTest"
style="position:absolute;top:0px;left:0;height:12;width:12;text-align:center">'+MyString[i]+'</div>');

Now if MyString contains 6 characters, I end up with 6 <div id="MyTest"> containers.

With IE I am able to access these containers as follows:

for (i=0; i < MyString.length; i++) {
var Obj=MyTest[i].style;
Obj.top=NewPositionTop;
Obj.left=NewPositionLeft+i;
}

Now with Firefox this didn't work
Javascript Error: file:///c:/test/mytest.js, line 209: MyTest[i] has no properties

and the Javascript Console suggests:
Warning: Element referenced by ID/NAME in the global scope. Use W3C standard document.getElementById() instead.

so I decided to use getElementById(), but keep getting errors.
I tried:
Obj1=document.getElementById("MyTest");
and then access Obj1[i].style.top/left but

Javascript Error: file:///c:/test/mytest.js, line 210: Obj1[i] has no properties

I also tried Obj=document.getElementById("MyTest")[i].style;

with the same result.

What is it that keeps me from accessing a specific entry in the getElementById("MyTest") list/array?

can anyone point me in the right direction?

Thanks, Robi

Michael Winter
On 13/07/2005 15:00, Robi wrote:

QUOTE
I have the following problem:
I populate a page with a specific amount of <div id="MyTest"> containers inside another <div> container.

You cannot do that. An id attribute value must be unique throughout an
entire document.

QUOTE
for (i=0; i < MyString.length; i++)
document.write('<div id="MyTest" [...]

As you're writing each element, you can append the value of i to produce
unique values.

[snip]

QUOTE
With IE I am able to access these containers [using a global variable with the same name]

Yes, you can. However, this is a terrible feature in my opinion, and you
shouldn't use it.

[snip]

QUOTE
Obj1=document.getElementById("MyTest");
and then access Obj1[i].style.top/left but

The getElementById method returns a single element, not a collection,
because there should only ever be one element with a matching value. If
you do have multiple potential matchs, the most common result is that
first (in source order) will always be returned.

Continuing the suggestion above, you can alter your code to:

var obj = document.getElementById('MyTest' + i);

if(obj && obj.style) {
/* ... */
}

[snip]

Mike

--
Michael Winter
Prefix subject with [News] before replying by e-mail.

ASM
Robi wrote:
QUOTE
I have the following problem:
I populate a page with a specific amount of <div id="MyTest"> containers inside another <div> container.

for (i=0; i < MyString.length; i++)
document.write('<div id="MyTest"
style="position:absolute;top:0px;left:0;height:12;width:12;text-align:center">'+MyString[i]+'</div>');

it is not allowed to have more than 1 element with same ID !

so try something as :

myHtml = '';
for (i=0; i < MyString.length; i++)
myHtml += '<div id="MyTest'+i+'"'+
'style="position:absolute;top:0px;left:0;height:12;width:12;text-align:center">'+
MyString[i]+'</div>');
document.write(myHtml);

Would be better to have a separte css to do not copy same thing x times

QUOTE
With IE I am able to access these containers as follows:

for (i=0; i < MyString.length; i++) {
var Obj=MyTest[i].style;
Obj.top=NewPositionTop;
Obj.left=NewPositionLeft+i;
}

yes that's IE way of work

try :
for (i=0; i < MyString.length; i++) {
var Obj = document.all?
MyTest[i].style :
document.getElementById?
document.getElementById('MyTest'+i).style :
document.layers['MyTest'+i] ;
Obj.top = NewPositionTop+'px';
Obj.left = NewPositionLeft+'px';
}

Notice that document.write()
is not an "up to date" way to script
See : createElement and appendChild
See also : cloneNode (ask to google)

--
Stephane Moriaux et son [moins] vieux Mac

Robi
Michael Winter wrote:
QUOTE
On 13/07/2005 15:00, Robi wrote:

I have the following problem:
I populate a page with a specific amount of <div id="MyTest"> containers
inside another <div> container.

You cannot do that. An id attribute value must be unique throughout an
entire document.

for (i=0; i < MyString.length; i++)
document.write('<div id="MyTest" [...]

As you're writing each element, you can append the value of i to produce
unique values.

[snip]

With IE I am able to access these containers [using a global variable with the same name]

Yes, you can. However, this is a terrible feature in my opinion, and you
shouldn't use it.

Thanks, will avoid/omit the use of it from now on.

QUOTE
Obj1=document.getElementById("MyTest");
and then access Obj1[i].style.top/left but

The getElementById method returns a single element, not a collection,
because there should only ever be one element with a matching value. If
you do have multiple potential matchs, the most common result is that
first (in source order) will always be returned.

Continuing the suggestion above, you can alter your code to:

var obj = document.getElementById('MyTest' + i);

if(obj && obj.style) {
/* ... */
}

well, I did "forget" to mention in my post, that that was the /workaround/
I used.
The script was written by someone else and I was trying to adapt it to work
at least in my browser as well. Somehow I did know that element IDs should
be unique in a document although when I saw this code I thought it was a
neat way to access the objects.

Thanks for your reply and for getting me out of my doubt if I had done it
correctly or not.

What I don't understand is why do you check for (obj && obj.style).
Wouldn't a check for just (obj.style) suffice? Besides, since I know I set
the style, wouldn't (obj) be enough?

Robi

Robi
ASM wrote:
QUOTE
Robi wrote:
I have the following problem:
I populate a page with a specific amount of <div id="MyTest"> containers inside another <div> container.

for (i=0; i < MyString.length; i++)
document.write('<div id="MyTest"
style="position:absolute;top:0px;left:0;height:12;width:12;text-align:center">'+MyString[i]+'</div>');

it is not allowed to have more than 1 element with same ID !
except for IE ;-) , but then, Microsoft has always been special ;-)


QUOTE
so try something as :

myHtml = '';
for (i=0; i < MyString.length; i++)
myHtml += '<div id="MyTest'+i+'"'+
'style="position:absolute;top:0px;left:0;height:12;width:12;text-align:center">'+
MyString[i]+'</div>');
document.write(myHtml);

Would be better to have a separte css to do not copy same thing x times

Thanks, I'll keep that in mind

QUOTE
With IE I am able to access these containers as follows:

for (i=0; i < MyString.length; i++) {
var Obj=MyTest[i].style;
Obj.top=NewPositionTop;
Obj.left=NewPositionLeft+i;
}

yes that's IE way of work

try :
for (i=0; i < MyString.length; i++) {
var Obj = document.all?
^^^^^^^^^^^^

[undefined] in my tests

I came up with
NS4=(document.layers)?1:0;
IE4=(document.all)?1:0;
W3C=(document.getElementById&&!document.all)?1:0;


QUOTE
MyTest[i].style :
document.getElementById?
document.getElementById('MyTest'+i).style :
document.layers['MyTest'+i] ;
Obj.top = NewPositionTop+'px';
^^^^

will need to keep this in mind too

QUOTE
Obj.left = NewPositionLeft+'px';
}

Notice that document.write()
is not an "up to date" way to script
See : createElement and appendChild
See also : cloneNode (ask to google)

as well as these :-)


Merci

Robi

Michael Winter
On 13/07/2005 19:26, Robi wrote:

QUOTE
Michael Winter wrote:

[snip]

QUOTE
var obj = document.getElementById('MyTest' + i);

if(obj && obj.style) {
/* ... */
}

[snip]

QUOTE
What I don't understand is why do you check for (obj && obj.style).
Wouldn't a check for just (obj.style) suffice?

If the call didn't succeed, obj will be null and trying to access a
property will cause the script to error out.

For instance, my version of Konqueror implements the
ViewCSS.getComputedStyle method, however it always returns null. You
should always check return values unless a method guarantees success, or
perhaps if you're in an environment where you can make certain
assumptions about which browsers are in use.

QUOTE
Besides, since I know I set the style, wouldn't (obj) be enough?

You're assuming that style property is supported. That isn't a safe bet
on the Web, at least.

In a similar fashion, you should check that the getElementById method is
supported before calling it. This style of defensive programming is
termed feature detection, where one examines the environment for support
of methods and properties before one goes about using them.


On 13/07/2005 19:39, Robi wrote:

[snip]

QUOTE
I came up with
NS4=(document.layers)?1:0;
IE4=(document.all)?1:0;
W3C=(document.getElementById&&!document.all)?1:0;

That is flawed. For instance, OmniWeb and Escape support the layers
collection. Similarly, OmniWeb, Opera, Konqueror, and Safari support the
all collection. Finally, just because a browser implements the
getElementById method doesn't mean it properly supports the W3C DOM.

Object inference (and browser detection in general) is not reliable and
doesn't actually tell you what you need to know: is a browser capable of
doing what I want it to?


As far as making object retrieval it's better to perform any tests once:

var getReferenceById = isGenericObject(document.getElementById)
? function(id) {
return document.getElementById(id);
}
: isObject(document.all)
? function(id) {
var result = document.all[id];

if(result) {
if(isGenericObject(result.item)) {
for(var i = 0,
n = result.length;
i < n;
++i)
{
if(id == result[i].id) {
return result[i];
}
}
} else if(id == result.id) {
return result;
}
}
return null;
}
: function() {return null;};

function isGenericObject(o) {
return isObject(o) || ('function' == typeof o);
}
function isObject(o) {
return 'object' == typeof o;
}

If you really want to bother supporting an obsolete browser like NN4,
you can follow the same pattern to add use of the layers collection.

[snip]

Hope that helps,
Mike

--
Michael Winter
Prefix subject with [News] before replying by e-mail.

ASM
Robi wrote:
QUOTE
ASM wrote:

it is not allowed to have more than 1 element with same ID !

Robi wrote:

except for IE ;-) , but then, Microsoft has always been special ;-)

Oh! any browser would be glad with what you want in ID :-)
clean JavaScript less, and W3C more less again


QUOTE
try :
for (i=0; i < MyString.length; i++) {
var Obj = document.all?

^^^^^^^^^^^^
[undefined] in my tests

Arrgghh ! :-(

QUOTE
I came up with
NS4=(document.layers)?1:0;
IE4=(document.all)?1:0;
W3C=(document.getElementById&&!document.all)?1:0;

why not.

QUOTE
See : createElement and appendChild
See also : cloneNode (ask to google)


as well as these :-)

yeap !
but
was if you'ld like to learn few more about DOM :-)
(there are so much possibilities using DOM)


--
Stephane Moriaux et son [moins] vieux Mac

ASM
Michael Winter wrote:
QUOTE
On 13/07/2005 19:26, Robi wrote:

Michael Winter wrote:

If the call didn't succeed, obj will be null and trying to access a
property will cause the script to error out.

DOM way functions all of them would start with
if(document.getElementById) {
to satisfy my NC4.5 :-)

QUOTE
Besides, since I know I set the style, wouldn't (obj) be enough?

You're assuming that style property is supported. That isn't a safe bet
on the Web, at least.

i.e. my NC4.5 :-)

QUOTE
In a similar fashion, you should check that the getElementById method is
supported before calling it.

Too late ! I did say it

QUOTE
As far as making object retrieval it's better to perform any tests once:

Keep this novel below to try it and for my archives
(script not so easy to follow)

QUOTE
var getReferenceById = isGenericObject(document.getElementById)
? function(id) {
return document.getElementById(id);
}
: isObject(document.all)
? function(id) {
var result = document.all[id];

if(result) {
if(isGenericObject(result.item)) {
for(var i = 0,
n = result.length;
i < n;
++i)
{
if(id == result[i].id) {
return result[i];
}
}
} else if(id == result.id) {
return result;
}
}
return null;
}
: function() {return null;};

function isGenericObject(o) {
return isObject(o) || ('function' == typeof o);
}
function isObject(o) {
return 'object' == typeof o;
}

If you really want to bother supporting an obsolete browser like NN4,
you can follow the same pattern to add use of the layers collection.

Wonderful ! there will be a 2nd season ? :-)




--
Stephane Moriaux et son [moins] vieux Mac

Robi
Michael Winter wrote:
QUOTE
On 13/07/2005 19:26, Robi wrote:

[snip]

QUOTE
I came up with
NS4=(document.layers)?1:0;
IE4=(document.all)?1:0;
W3C=(document.getElementById&&!document.all)?1:0;

That is flawed. For instance, OmniWeb and Escape support the layers
collection. Similarly, OmniWeb, Opera, Konqueror, and Safari support the
all collection. Finally, just because a browser implements the
getElementById method doesn't mean it properly supports the W3C DOM.

Ok, this is getting nightmarish.

I have noticed going to javascript websites
i.e. http://www.webreference.com/js/column44/appendchild.html
and clicking on the "run this script" links with my Firefox 1.0 agent
to see about ASM's suggestion and see the implementations, I get
"uncaught exceptions" which worry me, because it tells me that
every single method/object needs to be checked if it is supported
or available in the agent used (mine or someone elses).

([Exception... "Not enough arguments [nslDOMHTML.TableCellElement.cloneNode]" nsresult: "0x80570001
(NS_ERRORNS_ERROR_XPC_NOT_ENOUGH_ARGS)")

ergo, as you say:

QUOTE
Object inference (and browser detection in general) is not reliable and
doesn't actually tell you what you need to know: is a browser capable of
doing what I want it to?

and further:

QUOTE
As far as making object retrieval it's better to perform any tests once:

var getReferenceById = isGenericObject(document.getElementById)
? function(id) {
return document.getElementById(id);
}
: isObject(document.all)
? function(id) {
var result = document.all[id];

if(result) {
if(isGenericObject(result.item)) {
for(var i = 0,
n = result.length;
i < n;
++i)
{
if(id == result[i].id) {
return result[i];
}
}
} else if(id == result.id) {
return result;
}
}
return null;
}
: function() {return null;};

function isGenericObject(o) {
return isObject(o) || ('function' == typeof o);
}
function isObject(o) {
return 'object' == typeof o;
}

If you really want to bother supporting an obsolete browser like NN4,
you can follow the same pattern to add use of the layers collection.

Is there any sense in scripting at all? I mean, there's so many agents
supporting different methods, different objects, and those differently
alltogether that you'd need a whole script library for even the simplest
scripts.

Even websites, which should be able to handle this - since they "teach"
others how to do it - can't, as the above link shows.

ASM
Robi wrote:
QUOTE
Michael Winter wrote:

On 13/07/2005 19:26, Robi wrote:

I have noticed going to javascript websites
i.e. http://www.webreference.com/js/column44/appendchild.html

You didn't begin with a very easy tutorial

QUOTE
and clicking on the "run this script" links with my Firefox 1.0 agent
to see about ASM's suggestion and see the implementations, I get
"uncaught exceptions" which worry me, because it tells me that
every single method/object needs to be checked if it is supported
or available in the agent used (mine or someone elses).

([Exception... "Not enough arguments [nslDOMHTML.TableCellElement.cloneNode]" nsresult: "0x80570001
(NS_ERRORNS_ERROR_XPC_NOT_ENOUGH_ARGS)")

RhhhAaaaa ! les coquins !
Tey did forget 'true' everywhere here :
cloneNode()
->
cloneNode(true)

their last test page runs fine with this correction ( FF 1.04 Mac)


http://www.mozilla.org/docs/dom/domref/dom_shortTOC.html

--
Stephane Moriaux et son [moins] vieux Mac

Richard Cornford
Robi wrote:
QUOTE
Michael Winter wrote:
<snip
Object inference (and browser detection in general) is
not reliable and doesn't actually tell you what you need
to know: is a browser capable of doing what I want it to?

and further:

As far as making object retrieval it's better to perform
any tests once:
<snip
Is there any sense in scripting at all?

People climb mountains, I see no sense in that, yet still they are
climbed. There is a challenge in trying to learn to do something that is
not easy, a sense of achievement from doing what is not easy and
hopefully doing it well.

QUOTE
I mean, there's so many agents supporting different
methods, different objects, and those differently
alltogether that you'd need a whole script library
for even the simplest scripts.

One of the most important considerations in cross-browser scripting is
that some UAs do not support scripting at all, and those that do all
allow it to be disabled. This is not a situation that can be addressed
with scripting as such, but rather script/page/system design. What is
known as 'clean degradation', which does not mean 'silent failure' but
rather that whatever is presented to the user in the face of the absence
of client-side scripting, and/or the inability of the user agent to
provide the facilities that the script requires, still provides the
required content and acceptable functionality to the user.

Having designed for clean degradation it becomes less important to bend
over backwards to actively support old and unusual browsers because, so
long as the script performs proper feature detection so that it knows
when it will need to cleanly degrade (elects not to attempt to act), the
user will be getting access to the required content and acceptable
functionality. This means that it is quite acceptable to only provide
actively scripted enhancements for W3C DOM compliant browsers and (in so
far as it is not quite W3C DOM compliant) IE (for commercial reasons).
Thus the amount of script needed (and particularly the amount of code
branching) does not need to be too great. And, well designed, much of
what is written becomes easily re-usable.

Mike's getElementById emulation being an obvious example of a re-usable
component. It benefits from the realisation that the retrieval of a
reference to a DOM element is a common task. Other obviously common
tasks that require some degree of variation between different browsers
can similarly be encapsulated into functions, objects and/or components
for easy re-use. Leaving the majority of the task of programming
eventually operating at a level above the detail of the individual
browsers.

However, be cautious of monolithic DHTML libraries as you don't want
users to be downloading large chunks of code some of which they will
never be executing, and DHTML libraries are rarely written with clean
degradation in mind.

QUOTE
Even websites, which should be able to handle this -
since they "teach" others how to do it - can't, as
the above link shows.

It is very easy for individuals to create web pages purporting to teach
people about browser scripting. There is just nothing to stop them, so
if they don't know the issues, don't recognise or accept the issues, or
just cannot be bothered, the results will not be of much use to those
interested in cross-browser scripting.

Anyone can claim to "teach", even without experience or knowledge. Don't
trust anything just because it is in a web page (or, for that matter, a
book on browser scripting).

Richard.

Dr John Stockton
JRS: In article <[Email Removed]>, dated Wed, 13
Jul 2005 13:39:23, seen in news:comp.lang.javascript, Robi
<[Email Removed]> posted :
QUOTE

IE4=(document.all)?1:0;

Probably not a sensible thing to do - see FAQ - but

IE4 = !!document.all

gives the same more simply.

--
John Stockton, Surrey, UK. [email protected] Turnpike v4.00 IE 4
<URL:http://www.jibbering.com/faq/> JL/RC: FAQ of news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.

Robi
QUOTE
Notice that document.write()
is not an "up to date" way to script
See : createElement and appendChild
See also : cloneNode (ask to google)

Ok, so far I've been "messing" around with
document.createElement(str tag)
document.createTextNode(str value)
and so on, and now, I have questions about the amount of options:
Id=documentCreateAttribute('id'); id.value='div1'; Div1=setAttributeNode(id);
versus
Div1=setAttribute('id','div1');
versus
Div1.id='div1';

which one is "better"?

I also have another problem which I've been trying to solve:
I can't get hold of the "body" object.
It is there in the document, but whatever I do, I always end up with the error:
Body has no properties
or
Body.item(0) has no properties

here's an excerpt of my monster:
//var Body=(document.getElementsByTagName)?document.getElementsByTagName("body").item(0):document.body;
//var Div0=Body.appendChild(document.createElement("div"));
// above didn't work
var Body=(document.getElementsByTagName)?document.getElementsByTagName("body"):document.body;
var Div0=Body.item(0).appendChild(document.createElement("div"));
// and neither did these
Div0.id=BaseId; Div0.style.position='absolute';
Div0.style.top='0px'; Div0.style.left='0px';
var Div1=Div0.appendChild(document.createElement("div")); Div1.style.position='relative';

the appendChild() method seems to be the culprit.

quest ce que c'est?

Robi "psycho chicken"

ASM
Robi wrote:
QUOTE
Notice that document.write()
is not an "up to date" way to script
See : createElement and appendChild
See also : cloneNode (ask to google)


Ok, so far I've been "messing" around with
document.createElement(str tag)
document.createTextNode(str value)
and so on, and now, I have questions about the amount of options:

Wasn't it a good idea to go to see this profusion ? :-)

QUOTE
Id=documentCreateAttribute('id'); id.value='div1'; Div1=setAttributeNode(id);

on my idea :
foo = document.CreateAttribute('id')
is to create an attribute nammed 'foo',
'foo' then to be use where you want by setAttributeNode.
You can start creating an element
(usualy a tag as DIV or P but could bee a child of a tag as some text)

so in the document (virtual html code of page)
1) you create an element : createElement(tag)
2) you create a text : createTextNode(text)
3) you create an attribute : createAttribute(attribute)
3b) you create the meaning of this attribute : nodeValue = string;

stil this moment we have bits of virtual code sowed somewhere in
computer mind

All what that for ?
to easily (?!) use and re-use them
to be compatible with XLM HXML
to get dynamism (without run to server and back)

So, on next step : we have to organise them
i.e : to give an aign to each td of page
foo = document.createAttribute('style');
foo.nodeValue = "right";
T = document.getElementsByTagName('TD');
for(var i=0;i<T.length;i++) T[i].setAttributeNode('foo');

That was a simple example you can modify in DOM1 ou JS as :
for(var i=0;i<T.length;i++) T[i].align='right';
or
for(var i=0;i<T.length;i++) T[i].style.textAlign='right';
but it suposes you did catch all TDs (with JS I don't know how to do)

other example :
var montitre = document.createElement("h1");
var monTexte = document.createTextNode("A very dynamical page");
montitre.appendChild(monTexte); // inserts monTexte in h1
// determine/get a space (to set the title h1)
var passagesortie = document.getElementById("here");
// place the title (just in end of the space 'passagesortie')
passagesortie.appendChild(montitre);

Try to realise this example by JS (with document.write()?)
after page has loaded -> not possible

All these commands and functions are for dynamic javascript
Some dynamism can be set with old JS (move, resize, scroll, attributes)
but not creations and/or insertions after loading

One of most interest is cloneNode
i.e.
form with a table with one row (article price quantity total button:add)
table with an id and set to hidden and non-display
table followed by a span or div whom use is contener for next insertions
and with same table (with other id and displayed and visible)
on each click on add button
hop! you clone invible table then put it in end of reserved space
(that's to say after the last table of form)
set its id, display and visible
With only a simple single table of one row you can grow your light page
to heavy and at buyer's satisfaction.


QUOTE
versus
Div1=setAttribute('id','div1');
versus
Div1.id='div1';

which one is "better"?

All depends ;-)

QUOTE
I also have another problem which I've been trying to solve:
I can't get hold of the "body" object.

mybody = document.getElementsByTagName('BODY')[0];
(1st element in tags tree of value 'body')

QUOTE
//var Div0=Body.appendChild(document.createElement("div"));

supposing you'd cath body
what you wrote is : put a new div in end of body
better doing :
mybody = document.getElementsByTagName('BODY')[0];
myDiv = document.createElement("div");
to be abble to do :
for(var i=0;i<5;i++) {
myDiv = document.createElement("div");
myBody.appendChild(myDiv);
myBody.lastChild.id = 'Id_'+i;
}


QUOTE
the appendChild() method seems to be the culprit.

quest ce que c'est?

I don't know. What is culprit ?

c'est pour placer un element precedemment cree
that's to set an element previously created
it inserts the element just in end of space given
Like that, later, you can get it with lastChild

last example :
http://fr.selfhtml.org/javascript/objets/n...tm#append_child
(no real english version on this site)

<html><head><title>Test</title></head>
<body>
<ol id="Liste">
<li>Element</li>
</ol>
<script language="JavaScript" type="text/javascript">
<!--
document.getElementById("Liste").removeChild(document.getElementById("Liste").firstChild);

for(var i = 0; i < 10; i++) {
var newLI = document.createElement("li");
var numeroli = i + 1;
var nouveautexteli = document.createTextNode("It is list element "+
"number " + numeroli);
document.getElementById("Liste").appendChild(newLI);
document.getElementsByTagName("li")[i].appendChild(nouveautexteli);
}
//-->
</script>
</body></html>

remove the li
then create and insert 10 times : new li + new text in li

--
Stephane Moriaux et son [moins] vieux Mac


PHP Help | Linux Help | Web Hosting | Reseller Hosting | SSL Hosting
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2006 Invision Power Services, Inc.