Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

getElementByClass

2 views
Skip to first unread message

Kameleonten

unread,
Dec 20, 2005, 8:14:49 PM12/20/05
to
To make my navigation menu work in IE I have used this script. But it
doesn't work with classes. So when I now want to use a CMS that
genererates the navigation hierarchy that uses class instead of ID it
fails. How do I modify it so it works with CLASS instead of ID?

startList = function() {
if (document.all && document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}

node.onmouseout=function() {
this.className=this.className.replace(" over", "");
}
}
}
}
}
window.onload=startList;

----------------------------------------

Here is my experiment that doesn't work:

function getElementbyClass(classname){
var partscollect;

var inc=0
var alltags=document.all? document.all :
document.getElementsByTagName("*")

for (i=0; i<alltags.length; i++){
if (alltags[i].className==classname)
partscollect=alltags[i]
}
}


startList = function(){

if (document.all && document.getElementByClass) {
navRoot = document.getElementByClass("bulletmenu");

for (i=0; i < navRoot.partscollect.childNodes.length; i++) {
node = navRoot.partscollect.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}

node.onmouseout=function() {
this.className=this.className.replace(" over", "");
}
}
}
}
}

I don't have any javascript experience, but with Java I have .

Randy Webb

unread,
Dec 21, 2005, 12:19:13 AM12/21/05
to
Kameleonten said the following on 12/20/2005 8:14 PM:

> To make my navigation menu work in IE I have used this script. But it
> doesn't work with classes. So when I now want to use a CMS that
> genererates the navigation hierarchy that uses class instead of ID it
> fails. How do I modify it so it works with CLASS instead of ID?
>
> startList = function() {
> if (document.all && document.getElementById) {
> navRoot = document.getElementById("nav");
> for (i=0; i<navRoot.childNodes.length; i++) {
> node = navRoot.childNodes[i];
> if (node.nodeName=="LI") {
> node.onmouseover=function() {
> this.className+=" over";

It may or may not be the source of your problem. But, className's can
not contain a space. What you are doing in the onmouseover is adding "
over" to the className. That contains a space and will cause a problem.
might try: this.className+="over";

Also, if your classNames onmouseover will always have over appended to
the end, it might be better to simply remove the last 4 characters from
the className than to remove the sequence "over" from the className. If
the className is "myHoverClass" when you add "over" to it, it becomes
"myHoverClassover" and removing over will remove the first one, not the
last one so it becomes "myHClassover".

Or, change the remove to match the last one, not the first one.

--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/

Thomas 'PointedEars' Lahn

unread,
Dec 21, 2005, 5:18:03 AM12/21/05
to
Kameleonten wrote:

> To make my navigation menu work in IE I have used this script. But it
> doesn't work with classes. So when I now want to use a CMS that
> genererates the navigation hierarchy that uses class instead of ID it
> fails. How do I modify it so it works with CLASS instead of ID?
>
> startList = function() {

^^^^^^^^^
Undeclared global variable.

> if (document.all && document.getElementById) {

This does not make sense. You are not even using document.all,
yet testing for it. What should that accomplish anyway?

<URL:http://pointedears.de/scripts/test/whatami#inference>

> navRoot = document.getElementById("nav");

^^^^^^^


> for (i=0; i<navRoot.childNodes.length; i++) {

^
> node = navRoot.childNodes[i];
^^^^
Undeclared global variables.

> if (node.nodeName=="LI") {

Use HTMLElement::tagName instead.

> node.onmouseover=function() {
> this.className+=" over";

If the `class' attribute value of that element was empty before (default),
the new value could end up to be not Valid. HTML 4.01 defines the `class'
attribute value as a whitespace separated list of non-whitespace CDATA:

<URL:http://www.w3.org/TR/html4/struct/global.html#adef-class>

Also note that the specificity of a previously declared selector defines
whether changing `class' attribute value/className property has any effect
on the stylesheet cascade.

<URL:http://www.w3.org/TR/CSS2/cascade.html>

> }
>
> node.onmouseout=function() {
> this.className=this.className.replace(" over", "");
> }
> }
> }
> }
> }
> window.onload=startList;

Assign event listeners using EventTarget::addEventListener()
[W3C DOM Level 2 Events] or eventTarget.attachEvent() [IE DOM],
if possible.

Indent (especially posted) code using spaces, not tabs.
Corrected and pretty-printed, that is

...
<html>
<head>
...
<meta http-equiv="Content-Script-Type" content="text/javascript">
<script type="text/javascript">
/**
* @author
* (C) 2003, 2004 Thomas Lahn &lt;type...@PointedEars.de&gt;
* @partof
* http://pointedears.de/scripts/types.js
*/
function dhtml_isMethodType(s)
{
return (s == "function" || s == "object");
}

/*
* @author
* (C) 2004 Thomas Lahn &lt;dhtm...@PointedEars.de&gt;
* @partof
* http://pointedears.de/scripts/dhtml.js
*/
function registerEvent(o, sEvent, fListener, bUseCapture)
{
var result;

if (o)
{
if (dhtml_isMethodType(typeof o.addEventListener)
&& dhtml_isMethodType(typeof fListener))
{
o.addEventListener(sEvent, fListener, !!bUseCapture);
result = true;
}
else if (dhtml_isMethodType(typeof o.attachEvent)
&& dhtml_isMethodType(typeof fListener))
{
result = o.attachEvent("on" + sEvent, fListener);
}
else
{
o["on" + sEvent] = fListener;
result = (o["on" + sEvent] == fListener);
}
}

return result;
}

function startList()
{
if (isMethodType(typeof document.getElementById))
{
var navRoot = document.getElementById("nav");
if (navRoot && navRoot.childNodes)
{
for (var i = 0; i < navRoot.childNodes.length; i++)
{
var node = navRoot.childNodes[i];
if (node.tagName.toLowerCase() == "li")
{
node.onmouseover=function()
{
if (this.className)
{
this.className = this.className.replace(/\s*$/, " over");
}
else
{
this.className = "over";
}
}

registerEvent(node, 'mouseout',
function()
{
this.className = this.className.replace(/\s*over/, "");
});
}
}
}
}
}
</script>
</head>

<body onload="startList()">
...
</body>
</html>



> ----------------------------------------
>
> Here is my experiment that doesn't work:
>
> function getElementbyClass(classname){
> var partscollect;
>
> var inc=0

Unused variable.

> var alltags=document.all? document.all :
> document.getElementsByTagName("*")

You want to test whether `document.getElementsByTagName' refers to a
method before you call it. See above.



> for (i=0; i<alltags.length; i++){

^ ^^^^^^^^^^^^^^ inefficient
Undeclared global variable.

> if (alltags[i].className==classname)
> partscollect=alltags[i]

That would overwrite the previous value of partscollect with a reference
to the object referred to by `alltags[i]', therefore the function does not
return a collection as implied by your use of the method below.

> }
> }

As I said, the value of the `class' attribute, thus the value of the
`className' property, is a whitespace-separated list of non-whitespace
CDATA. The condition above will only apply if that list has only one
element. It should be

var aResult = [];

if (alltags && alltags.length)
{
for (var i = 0, len = alltags.length; i < len; i++)
{
var o = alltags[i];
if (new RegExp("\\b" + classname + "\\b")
.test(o.className))
{
aResult.push(o);
}
}
}

With the provision that the value of `classname' may not contain unescaped
characters considered special in RegExp. If it does and matching such
"wildcard" attribute values is not desired, the value of `classname' has
to be escaped properly before it can be used in the RegExp() argument.

> startList = function(){
^^^^^^^^^
See above.

> if (document.all && document.getElementByClass) {

The document.all test is again bogus.

And globally declared functions, such as your `getElementByClass', do not
automatically become properties of the (HTMLDocument) object referred to
by `document'. If you want that, you have to do

document.getElementByClass = functionReference;

before. Test with

if (dhtml_isMethodType(typeof getElementByClass))
{

otherwise.

> navRoot = document.getElementByClass("bulletmenu");

^^^^^^^
See above.



> for (i=0; i < navRoot.partscollect.childNodes.length; i++) {

^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^[1]
See above.

[1] This cannot work. If your getElementByClass() method worked as
intended, `navRoot' would refer to that collection. `partscollect'
is clearly defined locally through the `var' keyword. You are mixing
up contexts.

> node = navRoot.partscollect.childNodes[i];
^^^^
> [...]

See above.

> I don't have any javascript experience, but with Java I have .

In Java, the concept of execution context is much more strictly implemented
than in J(ava)Script/ECMAScript, so you should have noticed that.


HTH

PointedEars

Thomas 'PointedEars' Lahn

unread,
Dec 21, 2005, 5:19:31 AM12/21/05
to
Randy Webb wrote:

> [...] But, className's can not contain a space.

They certainly can, see my other followup.


PointedEars

Thomas 'PointedEars' Lahn

unread,
Dec 21, 2005, 5:26:41 AM12/21/05
to
Kameleonten wrote:

> [...]


> Here is my experiment that doesn't work:

> [...]

"Does not work" is a useless error description. [psf 4.11]

<URL:http://jibbering.com/faq/#FAQ4_43>


PointedEars

Kameleonten

unread,
Dec 21, 2005, 7:12:14 AM12/21/05
to
To clarify my problem. This is the code that works with ID, and I got
it from http://www.alistapart.com/articles/hybrid/:

/**************Start of working code **********/


startList = function() {
if (document.all && document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}

node.onmouseout=function() {

this.className=this.className.replace(" over", "");
}
}
}
}
}

window.onload=startList;
/**********End off working code ************/

How do I "convert" this script so I can use it with CLASS instead?

Some comments to PointedEars:

>In Java, the concept of execution context is much more strictly implemented
than in J(ava)Script/ECMAScript, so you should have noticed that.

>"Does not work" is a useless error description. [psf 4.11]

As I said I don't have any JavaScript experience. That means that I
don't know the syntax or "the concept of execution context". It also
means that I don't have a debug tool for JavaScript and thats why I use
the useless error description. I still hope that you can help me with
this problem.

VK

unread,
Dec 21, 2005, 7:42:19 AM12/21/05
to

Randy Webb wrote:
> className's can
> not contain a space. What you are doing in the onmouseover is adding "
> over" to the className. That contains a space and will cause a problem.
> might try: this.className+="over";

Sorry, but not true at all. One can apply any amount of space-separated
classes to a single element:
<li class="class1 class2 class3">
in which case className will be "class1 class2 class3"
This is what the posted code does: atop of existing class it adds extra
class with mouseover styling.

To OP:
DOM doesn't have getElementByClassName or getElementsByClassName. There
are more or less functional emulations of these methods. The best and
the most time-checked is from prototype.js library
<http://prototype.conio.net/>

But much simplier/safer is keep using id's especially with such code
where className will be changed dynamically.

sucki...@gmail.com

unread,
Dec 21, 2005, 2:49:23 PM12/21/05
to
Hi,

The following javascript sample functions might be able to help:

http://www.suckingfish.com/view.do?crumb_id=dsid_1067

Good luck,

Matt

Thomas 'PointedEars' Lahn

unread,
Dec 22, 2005, 9:33:17 AM12/22/05
to
Kameleonten wrote:

> To clarify my problem. This is the code that works with ID,

"works with ID"?

So you should ask _them_, yes?

> [...]


> How do I "convert" this script so I can use it with CLASS instead?

It is already using the `class' attribute (through the `className'
property), but it is using it wrong or, better put, not reliably.

I already told you how to make it work reliably. If you do not
understand parts of what I posted, you should quote that parts
and ask about them, not post the same nonsense again.

[Repaired quote]


>> In Java, the concept of execution context is much more strictly
>> implemented than in J(ava)Script/ECMAScript, so you should have

>> noticed that. [...]


>> "Does not work" is a useless error description. [psf 4.11]
>
> As I said I don't have any JavaScript experience. That means that I
> don't know the syntax or "the concept of execution context".

If you knew _Java_ (Java != JavaScript), you should have recognized that
the `partscollect' variable was local, without any JavaScript knowledge;
because AFAIK in Java, all variables defined in local context are local.



> It also means that I don't have a debug tool for JavaScript
> and thats why I use the useless error description.

I pointed you to a description about debugging!

> I still hope that you can help me with this problem.

I still hope you are willing to _learn_.

<URL:http://jibbering.com/faq/faq_notes/pots1.html>


PointedEars

0 new messages