PDA

View Full Version : getElementByClassname problem never figured out..



riptide
05-31-2012, 10:21 AM
I went looking back at some one my old post and then on the web. I haven't been able to fine a working getelementbyclassname function that doesn't use jqery.
It seems like there should be some but most don't have demo pages or don't show you what to put in your html.

here is what I have

script above the body

function getElsByClassName(classname){
var rv = [];
var elems = document.getElementsByTagName('div')
if (elems.length){
for (var x in elems ){
if (elems[x] && elems[x].className && elems[x].className == classname){
rv.push(elems[x]);
}
}
}
return rv;
}


html

<div id="tileM" onclick="getElsByClassName('switchM').classname='Tname'"
I'm just trying to get this div to change the class of another div when clicked.
it seems like it should be so easy but no code I've used has worked.
I do have a better understanding when it's the div with the desired class that calls the function on it's self. scripts like that work. I'm not getting any errors but nothing is happening.
I think I never figured out how to get a function like this to work. I though I had something on my hard drive where I had worked it out but I didn't find anything.

I would appreciate it if some one can help me with this one issue. there are only certain things I frequently need solutions for. This is the last one.

It needs to be compatible with IE6. And I can't use a script library cause it has to be totally self contained.

jscheuer1
05-31-2012, 10:58 AM
That getElsByClassName function is primitive in that the elements it examines must have the exact class and only the exact class being looked for (but elements may have more than one class) and is limited to only examining div elements. This may or may not adequate for your purposes.

In browsers that support it, the real getElementsByClassName returns a nodelist - an array like list of elements. The getElsByClassName function, and all of the other functions like it return a true array. Regardless of which you have (nodelist or true array) you cannot set anything on the entire list or array without looping through it. And you cannot set anything on a particular member of the list or array without having a numeric reference to it.

There's no such thing as .classname, it's .className

So, assuming the getElsByClassName function, though limited and primitive is adequate to the task of finding the elements you need it to find, you would still need to loop through its results and use the proper syntax on each of those (even if there's only one) for it to do anything. Something like:


<div id="tileM" onclick="var els = getElsByClassName('switchM'); for (var i = els.length - 1; i > -1; --i){els[i].className='Tname';}"

If you want a better function for getting elements by their class name in browsers that don't have one, see:

http://www.webdeveloper.com/forum/showthread.php?t=198227

for alternatives and a robust discussion upon their merits.

vwphillips
05-31-2012, 12:00 PM
I use



function bycls(nme,el){
for (var reg=new RegExp('\\b'+nme+'\\b'),els=el.getElementsByTagName('*'),ary=[],z0=0; z0<els.length;z0++){
if(reg.test(els[z0].className)){
ary.push(els[z0]);
}
}
return ary;
}

jscheuer1
05-31-2012, 02:05 PM
Vic, I thought that was the way to go too, until I read the thread referenced in my previous post. Using that regex and searching for a class of 'title' will give a false positive on an element like:


<div class="title-div">

If you change it to:


function bycls(nme,el){
el = el || document; // assume document if no el argument is given
for (var reg=new RegExp('\\W'+nme+'\\W'),els=el.getElementsByTagName('*'),ary=[],z0=0; z0<els.length;z0++){
if(reg.test(els[z0].className)){
ary.push(els[z0]);
}
}
return ary;
}

It works correctly on that, but is less efficient than it could be. That's only important if it has to iterate over tons of elements, but that situation could arise on a page with a lot of HTML code on it. And it still doesn't exactly mimic getElementsByClassName(), which returns a nodelist, not an array and can take more than one class name as an argument (from the specification):


The getElementsByClassName(classNames) method takes a string that contains a set of space-separated tokens representing classes. When called, the method must return a live NodeList object containing all the elements in the document, in tree order, that have all the classes specified in that argument.

I don't think there's any way to create a nodelist, but accepting more than one class name is doable. Also, it might be good to fall forward to the browser's native getElementsByClassName if it has one.

BTW:


getElementsByTagName('*')

and:


ary.push(els[z0])

will fail in IE less than 6. Or it might be IE less than 5.5, I forget which. It might be different for each. Push is less than 5.5, I'm not sure about the other, it's 5.5 or 6. I use a test for push:


if (![].push){
Array.prototype.push = function(){
var a = arguments;
for(var i = 0; i < a.length; ++i){
this[this.length] = a[i];
}
return this.length;
};
}

But the other one, the substitute is (some browsers that identify .getElementsByTagName as a function don't do .getElementsByTagName('*')) document.all, or el.all, so if I'm branching for .getElementsByTagName('*'), I test the availability of the .all method first and use it if available.

Generally one can leave out these ancient browsers, they're incapable of rendering your average modern web page, but it depends upon the scope of script, what browsers it has to accommodate. There certainly are folks out there still using IE 5 and 5.5.

vwphillips
05-31-2012, 03:43 PM
function bycls(nme,el){
el = el || document; // assume document if no el argument is given
for (var reg=new RegExp('\\W'+nme+'\\W'),els=el.getElementsByTagName('*'),ary=[],z0=0; z0<els.length;z0++){
if(reg.test(els[z0].className)){
ary.push(els[z0]);
}
}
return ary;
}

interesting but needs(in red)


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

<html>

<head>
<title></title>
</head>

<body>
<div class="title-div">
<script> vic=0; </script>
<form name=Show id=Show style="position:absolute;visibility:visible;top:700px;left:0px;" >
<input size=100 name=Show0 >
<input size=10 name=Show1 >
<input size=10 name=Show2 >
<input size=10 name=Show3 >
<input size=10 name=Show4 >
<input size=10 name=Show5 >
<input size=10 name=Show6 >
<input size=10 name=Show7 >
<input size=10 name=Show8 >
<input size=10 name=Show9 ><br>
<textarea name=TA rows=1 cols=100 ></textarea>
</form>
<script type="text/javascript">
<!--
function bycls(nme,el){
for (var reg=new RegExp('\\W'+nme+'\\W'),els=el.getElementsByTagName('*'),ary=[],z0=0; z0<els.length;z0++){
if(reg.test(' '+els[z0].className+' ')){
ary.push(els[z0]);
}
}
return ary;
}
document.Show.Show0.value=bycls('title-div',document);

//-->
</script></body>

</html>

jscheuer1
05-31-2012, 04:34 PM
I think we're both wrong, mine failed on a single class name with no spaces, yours (if I understand it correctly) erroneously reports 2 matches here:


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
function bycls(nme,el){
el = el || document;
for (var reg=new RegExp('\\W'+nme+'\\W'),els=el.getElementsByTagName('*'),ary=[],z0=0; z0<els.length;z0++){
if(reg.test(' '+els[z0].className+' ')){
ary.push(els[z0]);
}
}
return ary;
}
</script>
</head>
<body>
<div class="title-span"></div>
<div class="title"></div>
<script type="text/javascript">
alert(bycls('title').length);
</script>
</body>
</html>

The regex finally adopted by most respondents in the thread I referred to is perhaps the solution (substitute nme for className to make it a drop in replacement):


new RegExp("(?:^|\\s)" + className + "(?:$|\\s)")

works with the above example. Potentially the best solution in that thread was:

http://www.webdeveloper.com/forum/showpost.php?p=964064&postcount=35

It might still benefit from one or more of the efficiencies mentioned in the earlier posts that it left out, like testing for the equality of a single class name first before applying the regex test. But that might make it less faithful to the specification.

And its author says right out it's not fully tested.

It also assumes an array is what's wanted and when falling forward converts the nodelist to an array. This can actually be good. Nodelists behave erratically cross browser. Some browsers add to/subtract from them if the DOM changes, others do not. With an array, neither of those will happen, so you know what to expect.

In my mind it's best feature is the callback which prevents having to iterate over the array again to perform whatever action is desired.

Added Later:

I tried out that function from that post that had impressed me. It had several problems. Here's a corrected version with my other additions (push for non-push browsers, document.all for those that support it that might not support getElementsByTagName in some or all of its forms) included:


/**
* @param string required Class name or names to find
* @param string optional Tag name to search for
* @param object optional DOM node to search from
* @param func optional Callback function executed on each iteration.
* Receives two arguments, index and DOM node
* @return array Array of matching DOM nodes
*/

function getElementsByClassNameCustom(cname, tagName, parent, callback) {
tagName = tagName || "*";
parent = parent || document;
callback = callback || function(){};
var el = null;
var matches = [];
var i = 0, j = 0;
var els = document.all && !window.opera? (tagName === '*'? parent.all : parent.all.tags(tagName)) : parent.getElementsByTagName(tagName);
var cnames = cname.split(' ');

function testallnames(name){
var cname, reg;
while (cname = cnames[j++]){
reg = new RegExp("(?:^|\\s)" + cname + "(?:$|\\s)");
if(!reg.test(name)){return false;}
}
return true;
}

while (el = els[i++]) {
j = 0;
if ( testallnames(el.className) ) {
callback( matches.push(el)-1, el);
}
}

return matches;
}

function getElementsByClassNameNative(cname, tagName, parent, callback) {
parent = parent || document;
callback = callback || function(){};

var els = parent.getElementsByClassName(cname, tagName);
var el;
var i = els.length;
var matches = [];

// Wrap the element collection in an Array
while (el = els[--i]) {
callback( matches.push(el)-1, el);
}

return matches.reverse();
}

window.getElementsByClassName = getElementsByClassNameCustom;//!document.getElementsByClassName ? : getElementsByClassNameNative;

if (![].push){
Array.prototype.push = function(){
var a = arguments;
for(var i = 0; i < a.length; ++i){
this[this.length] = a[i];
}
return this.length;
};
}

Example usage, utilizing all of the available parameters on two class names:


getElementsByClassName('title title-span', 'div', document.body, function(i, el){el.style.display = 'none';})

Using only the required on a single class name:


getElementsByClassName('title')

Note: The specification requires that, in the case of two or more class names, only those elements with all of the classes should be returned.

Usage for the original question:


<div id="tileM" onclick="getElementsByClassName('switchM', '', '', function(i, el){el.classname='Tname'});"

ApacheTech
06-01-2012, 01:37 AM
Thanks JS. I've been looking for a cross browser version of that for a while and I hit the same problem as you mentioned. The corrected function you posted works like a charm.

Added to code library of useful functions. :D (With credit of course.)

jscheuer1
06-01-2012, 02:07 AM
Here's an even better version:


/* @param string required Class name or names (space separated) to find, must be the first parameter

Optional Parameters in any order:
* @param string optional Tag name to search for
* @param object optional DOM node to search in
* @param function optional Callback function executed for each element found.
Receives two arguments, the element, the index in the array of the element.

* @return array Array of matching DOM nodes before callback if any, regadless of if its action removing it from the nodelist */

;(function(){

function testallnames(name, cnames){
var names = name.split(' '), j = -1, n = names.length, nameObj = {}, aname, cname;
while ((aname = names[--n])){
nameObj[aname] = true;
}
while ((cname = cnames[++j])){
if(!nameObj[cname]){return false;}
}
return true;
}

var getEls = (function(){
return document.all && !window.opera? function(tagName, parent){
return tagName === '*'? parent.all : parent.all.tags(tagName);
} : function(tagName, parent){
return parent.getElementsByTagName(tagName);
};
})();

function getElementsByClassNameCustom() {
var a = arguments.length - 1, t, arg, cname, tagName, parent, callback;
for (a; a > -1; --a){
arg = arguments[a];
if(!arg){continue;}
t = typeof arg;
t === 'function'? callback = arg : t === 'object'? parent = arg : a? tagName = arg : cname = arg;
}
if(!cname || typeof cname !== 'string'){throw(new Error('Not Enough Arguments, getElementsByClassName expects at least one class name as an argument.'));}
tagName = tagName || "*";
parent = parent || document;
callback = callback || function(){};
var el = null;
var matches = [];
var i = -1;
var els = getEls(tagName, parent);
var cnames = cname.split(' ');

while ((el = els[++i])) {
j = -1;
if ( testallnames(el.className, cnames) ) {
callback(el, matches.length);
matches[matches.length] = el;
}
}

return matches;
}

function getElementsByClassNameNative() {
var a = arguments.length - 1, t, arg, cname, tagName, parent, callback;
for (a; a > -1; --a){
arg = arguments[a];
if(!arg){continue;}
t = typeof arg;
t === 'function'? callback = arg : t === 'object'? parent = arg : a? tagName = arg : cname = arg;
}
if(!cname || typeof cname !== 'string'){throw(new Error('Not Enough Arguments, getElementsByClassName expects at least one class name as an argument.'));}
parent = parent || document;
callback = callback || function(){};

var els = parent.getElementsByClassName(cname, tagName);
var el;
var i = els.length;
var matches = [];

while ((el = els[--i])) {
callback(el, matches.push(el) - 1);
}

return matches.reverse();
}

window.getElementsByClassName = !document.getElementsByClassName? getElementsByClassNameCustom : getElementsByClassNameNative;
})();

Advantages/Changes:


No regular expressions for much faster lookups when the native getElementsByClassName function is missing.


Optional parameters are truly optional in that they may come in any order.


Only one function name exposed to the global scope (there were three before)


The method for getting elements by tag name when there's no native getElementsByClassName function is set once onload of the page, rather than branched out each time the function is used.


Callback function now uses the DOM element as first parameter, index as second as most callbacks will be to the element itself.


Throws an informative error if there is no class name argument.


Array.push for those that lack it eliminated, since only non getElementsByClassName browsers would need it, native methods used for the custom function.


Usage for the original question in this thread:


<div id="tileM" onclick="getElementsByClassName('switchM', function(el){el.classname = 'Tname';});"

The other usages from my previous post are the same.

riptide
06-01-2012, 08:27 AM
okay so there really wasn't any good classname function on the web. So thank you for making a good one. This is less complicated the the ultimate version. I know the one I first posted didn't have any iteration going on in it. I was sleepy and if I had been more awake I would have been trying to use something else. The browser that I'm coding in does have getElementsByClassName so using any function with that name probably caused problems.

anyway

<div id="tileM" onclick="getElementsByClassName('switchM', function(){this.classname = 'Tname';});"

The part that's in red it is unfamiliar coding why do I add function()
scratch that I understand what function is and why it's being called

and the {;} now why am I adding this.classname. I thought 'this' would refer to the element that is calling the function which would be tileM. is it referring to switchM?
I tired using this script and it doesn't work but it's not giving an error. I had to link it to an external script. Did this need to go in the html or is this related to using this.classname
I will check in other browsers in a second. I'm in firefox now.

jscheuer1
06-01-2012, 10:19 AM
First off, I've changed the code yet again. See my previous post which has now been edited to reflect that. The syntax for your original question is now:



<div id="tileM" onclick="getElementsByClassName('switchM', function(el){el.classname = 'Tname';});"

Also edited in the previous post to reflect that. None of these latest changes would affect its performance in IE 6+ or other modern browsers though for the use you're putting it to.

But to answer your new question:

The this keyword is whatever we tell the browser it is. In the callback it was the element(s) selected by the getElementsByClassName function. However, the syntax for telling that to the browser didn't exist in IE 5, so now I'm passing it in as a parameter, which BTW was the original method.

And ordinarily in that scenario this would be the element clicked, except that it's not in the function that executes onclick, it's in the function that executes on each element match of the selected class name(s). But, as I say, if you use the latest revised code, you won't have to worry about that anyway, the element is now being passed as a parameter.

Making the code external is no problem. In fact nothing you mention sounds like a problem.

This code has now been tested fairly thoroughly by myself and ApacheTech. That's not to say that there can't be any other tweaks required for situations I've not yet anticipated. But it's likely that if you're having problems using it, there's something else wrong on the page and/or its resources than this code.

Either way:

If you want more help, please include a link to the page on your site that contains the problematic code so we can check it out.

riptide
06-02-2012, 11:50 PM
Well
onclick="document.getElementsByClassName('switchM').className='switchMOff'"
and
onclick="document.getElementsByClassName('switchM').classname='switchMOff'"

don't work in a browser where getElementsByClassName is supposed to be supported IE 8 and Fire Fox 4. I could test it in opera but I don't expect any difference. I did this to see if it was something wrong with how the cold is being called or something else. I had a really hard time trying to check my browser for implementation on other websites. So I think it's only my page where it's failing.


/*main page-div for tile categories*/
.switchM {
position:absolute;
display:block;
z-index:10;
left: 0px;
top:45px;
width:755px;
height:551px;
padding: 10px;
}

/*main page-div for tile categories hidden*/
.switchMOff{
position:absolute;
display:none;
z-index:-1;
left: 0px;
top:45px;
}

There is no reason for this failure in the CSS


<div id="PorcFT" class="switchM" > These are Floriad tile's porcelain tiles. There are many to choose from.</div>

Nothing in the html of that div


I will try adding the native document.getElementsByClassName as an onload to the body tag. I got nothing even when I dropped the document part.


what do you think could be wrong?

jscheuer1
06-03-2012, 02:27 AM
Well
onclick="document.getElementsByClassName('switchM').className='switchMOff'"
and
onclick="document.getElementsByClassName('switchM').classname='switchMOff'"

don't work

Of course not because it's getElements . . . , what it gets you is a list of elements. You would either have to pick one and/or iterate over all of them to do anything with one or more of them. Even if there's only one, it's still a list, a list of one.

Just like you cannot do:


getElementsByName('someName').className = 'red';

nor:


getElementsByTagName('div').style.display = 'none';

This is unlike getElementById which is singular and returns one and only one element and that will either throw an error or act erratically if there are more than one element with the id.

In browsers supporting getElementsByclassName you can do this:


onclick="var sms = document.getElementsByClassName('switchM'), sml = sms.length, sm; while((sm = sms[--sml])){sm.className = 'switchMOff';}"

Or to put the same code in a function with easier to understand terms and commented to show what's happening:


function switchMsOff(){
var switchMs = document.getElementsByClassName('switchM'); // gets a collection of all class switchM elements
var switchMsLength = switchMs.length // sets a counter equal to the length of that collection
var switchM; // reserve a var for use in the while loop, it will represent each element in turn
while((switchM = switchMs[--switchMsLength])){ // counting backward, each time there's an element left in the list
switchM.className = 'switchMOff'; // set it's className to switchMOff
}
}

Then your onclick would be:


onclick="switchMsOff();"

Note: Iteration is done in reverse order because as you change an element's className in this case it will remove it from the list of elements. If you were to start at the beginning and count up, that would either cause an error or result in elements being missed. That is assuming there are more than one element in the list.

If there's only one element on the page with the target className or you only want to change the class of the first one of two or more that qualify, you can do:


onclick="document.getElementsByClassName('switchM')[0].className='switchMOff'"

But that has potential problems. Say there's only one. If you click again it's already changed, so there are now none and you will get an error.

So it's best to iterate over them anyway. If there are none, the loop will never start and there will be no error.

riptide
06-03-2012, 07:41 AM
Hu so it's not like document.getelementbytagname I would think it would work the exact same way.
Well I probably would have figured out I couldn't get it to work that way if I found more test pages.

Anyway I'm still not getting your function to work. It's not throwing an error though. I don't have any tools that can tell me where the problem is.
I don't have any browser that doesn't support getElementsByClassName to test for some kind of conflict.
I'm using
onclick="getElementsByClassName('switchM', function(el){el.classname = 'switchMOff';});"

wait I think I see the problem. I'll get back to you tomorrow.

jscheuer1
06-03-2012, 08:52 AM
I don't have any browser that doesn't support getElementsByClassName to test

IE 8 or less will do. If the earliest IE you have is IE 9, you can put it in compatibility mode or in IE 8 or IE 7 mode.

There is no:

"document.getelementbytagname"

There is a:

document.getElementsByTagName

and it does work like that, almost exactly like that. At least according to specification it's supposed to. There may be some subtle differences. But they both are supposed to return a live node list. In some browsers they do, in others it's only a static array like collection of the elements.

And you're right, I've been looking around the web and I can't find any decent examples of how to use browsers' native getElementsByClassName.

There are a lot of folks who say they have a function that works like it, most of those are limited or wrong. And there are some explanations of how to use browsers' native getElementsByTagName function, but they're all either too simplistic, wrong, or too advanced.

I see the problem with what you're doing and my code. Since you're presumably doing something like so:


<div id="tileM" onclick="getElementsByClassName('switchM', function(el){el.className = 'switchMOff';});">
This is the div that switches them off, click it
</div>

The assumed this keyword bypasses the script, it's as if you had:


<div id="tileM" onclick="this.getElementsByClassName('switchM', function(el){el.className = 'switchMOff';});">
This is the div that switches them off, click it
</div>

which would then use the browser's native getElementsByClassName function as it applies to the document and other document element objects.

Since there are no elements with the class of switchM in the div itself, it does nothing and gives no error.

You could do:


<div id="tileM" onclick="window.getElementsByClassName('switchM', function(el){el.className = 'switchMOff';});">
This is the div that switches them off, click it
</div>

and it would work. But that's not a great situation. What we should do is name our function something that can't be confused with native code, like elementsByClassName.

I made a few other improvements, so here it is yet again with those and the new name:


/* @param string required Class name or names (space separated) to find, must be the first parameter

Optional Parameters in any order:
* @param string optional Tag name qualifier to further limit the search for nodes
* @param object optional DOM node to search in
* @param function optional Callback function executed for each element found.
Receives two arguments: the element, the index in the returned array of the element.

* @return array Array of matched DOM nodes before callback if any,
regardless of whether or not callback removes the current node from the nodelist */

;(function(){

function testallnames(name, cnames){
var names = name.split(re), j = cnames.length, n = names.length, nameObj = {}, aname, cname;
while ((aname = names[--n])){
nameObj[aname] = true;
}
while ((cname = cnames[--j])){
if(!nameObj[cname]){return false;}
}
return true;
}

var getEls = (function(){
return document.all && !window.opera? function(tagName, parent){
return tagName === '*'? parent.all : parent.all.tags(tagName);
} : function(tagName, parent){
return parent.getElementsByTagName(tagName);
};
})(), errorreport = 'Not Enough Arguments, elementsByClassName expects at least one class name as its first argument.',
re = /\s/;

function getElementsByClassNameCustom() {
var a = arguments.length - 1, t, arg, cname, tagName, parent, callback;
for (a; a > -1; --a){
arg = arguments[a];
if(!arg){continue;}
t = typeof arg;
t === 'function'? callback = arg : t === 'object'? parent = arg : a? tagName = arg : cname = arg;
}
if(!cname || typeof cname !== 'string'){throw(new Error(errorreport));}
tagName = tagName || "*";
parent = parent || document;
callback = callback || function(){};
var el = null;
var matches = [];
var i = -1;
var els = getEls(tagName, parent);
var cnames = cname.split(re);

while ((el = els[++i])) {
if ( testallnames(el.className, cnames) ) {
callback(el, matches.length);
matches[matches.length] = el;
}
}

return matches;
}

function getElementsByClassNameNative() {
var a = arguments.length - 1, t, arg, cname, tagName, parent, callback;
for (a; a > -1; --a){
arg = arguments[a];
if(!arg){continue;}
t = typeof arg;
t === 'function'? callback = arg : t === 'object'? parent = arg : a? tagName = arg : cname = arg;
}
if(!cname || typeof cname !== 'string'){throw(new Error(errorreport));}
parent = parent || document;
callback = callback || function(){};

var els = parent.getElementsByClassName(cname, tagName);
var el;
var i = els.length;
var matches = [];

while ((el = els[--i])) {
callback(el, matches.push(el) - 1);
}

return matches.reverse();
}

window.elementsByClassName = !document.getElementsByClassName? getElementsByClassNameCustom : getElementsByClassNameNative;
})();

Usage is the same except for the new name. For what you're trying it would be something like:


<div id="tileM" onclick="elementsByClassName('switchM', function(el){el.className = 'switchMOff';});">
This is the div that switches them off, click it
</div>

riptide
06-03-2012, 10:05 PM
The assumed this keyword bypasses the script, it's as if you had:

Code:


<div id="tileM" onclick="this.getElementsByClassName('switchM', function(el){el.className = 'switchMOff';});">
This is the div that switches them off, click it
</div>

which would then use the browser's native getElementsByClassName function as it applies to the document and other document element objects.

Since there are no elements with the class of switchM in the div itself, it does nothing and gives no error.

You could do:



<div id="tileM" onclick="window.getElementsByClassName('switchM', function(el){el.className = 'switchMOff';});">
This is the div that switches them off, click it
</div>

and it would work. But that's not a great situation. What we should do is name our function something that can't be confused with native code, like elementsByClassName.

well that's the thing I can put document.getElementById on any item and it can function a a control switch for a completely unrelated object. So yeah that's why I was worried about the whole this keyword.

What's wrong with window.getElementsByClassName it seems like a good solution? It should search the whole HTML page right.
I'll try using your new code. I really need to learn javascript; I'm starting to get a better at understanding the logic though.
I don't have the best access to books since I've moved to a small town. So are they any online videos that can introduce me to javascript. What information I had on javascript was bad code and outdated.

jscheuer1
06-04-2012, 04:49 AM
I may have misunderstood before, but I thought your initial concern with this was in the callback. That's a separate issue. There it referred to each element that qualified via its class name. The only reason I took it out of there was that the syntax required to make it mean that doesn't exist in IE 5.

The literal meaning of this, if I understood correctly, is what you were concerned with there. Here it's the assumed/implied presence of this. Like if you do:


<a href="somepage.htm" onclick="alert(href);">Some Page</a>

Even though href is technically undefined, it will assume this.href and alert something like:


http://www.somedomain.com/somefolder/somepage.htm

So, although this is involved, it's in a different way.

Using window. forces the browser to look at the item as a property of the window instead of as one of the element:


<a href="somepage.htm" onclick="alert(window.href);">Some Page</a>

alerts 'undefined'.

But with our code, since we've already defined a getElementsByClassName property of the window as a function, it will use that.

It's not wrong, just "not a great situation". It involves more typing to code for when you use it and is prone to the very issue we're discussing should you or anyone else using the code forget. It's tempting to forget because it will work without window. in most cases. By using a name that's not already a native function in some browsers, we avoid that entirely. We don't have to remember to type out window. in certain situations. It will work without the window. prefix virtually anywhere we use it.



I'm not aware of any good videos on javascript. I remember a thread where I think someone mentioned some that they liked but I can't find it right now.

Ask in the lounge, I'm sure there are other members with suggestions.

Note: There are at least two things going on in this thread. One is helping you of course. The other is development of the elementsByTagName code for cross browser use. So please bear with me if the code changes. I just saw a way to go with the this keyword in the callback again, this time it works in IE 5, but I'm not sure I'll be adding that in the finished version. There are some other changes I will be making. When it's done, I'm going to Blog it. But what we have here now (the latest in this thread) is serviceable.

riptide
06-07-2012, 02:37 AM
Great! I was thinking you should put the code somewhere for everyone to see. You've already helped me enough. I have the code working in my site. I'll go check out the lounge.