Forum Moderators: open

Message Too Old, No Replies

adapting script "get by class"

how do you change '=='?

         

ctoz

3:25 am on Jul 4, 2007 (gmt 0)

10+ Year Member



Hello,

Slow learner here... here's the original script, without the specifics:

function whatever() {
for (i=0;i<document.getElementsByTagName("div").length; i++) {
if (document.getElementsByTagName("div").item(i).className == "something")
{document.getElementsByTagName("div").item(i).style.someCSS = "something Different"} }}

I have a whole bunch of divs, and I want to give each of them six different classes, eg
<div class="oneA twoB threeA fourB fiveA sixA">
<div class="oneB twoA threeA fourB fiveA sixB"> etc.
I want to access the divs several times, each time according to a different class. How do I say, for example, "get the divs which have oneA in their class"?

It looks like there should be some way to change the == in this line of original script:
if (document.getElementsByTagName("div").item(i).className == "something")

cheers

ctoz

daveVk

4:09 am on Jul 4, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



if (document.getElementsByTagName("div").item(i).className.indexof("something") > -1 )

should work, someone have cooler solution?

ctoz

11:19 am on Jul 4, 2007 (gmt 0)

10+ Year Member



Sorry, that's not working: tried as linked script and in head of doc.

Doing some reading, but not confident about technicalities... Would it be possible to use charAt() method? Eg, with <div class ="A B A A B B">, as in "if the character at index position 0 is A"
...so i tried it before posting. Eureka, it works:

function hideYang1() {
for (i=0;i<document.getElementsByTagName("div").length; i++) {
if (document.getElementsByTagName("div").item(i).className.charAt(0)== "A"){
document.getElementsByTagName("div").item(i).style.visibility = "hidden"}}}

Next question:
how to add the next 'if/then' bit to the foregoing? eg,

if (document.getElementsByTagName("div").item(i).className.charAt(0)=!"A"){
document.getElementsByTagName("div").item(i).style.color = "red";

Thee are more stages to this script where I'll need hand-holding, but one at a time...

cheers

CT

Bernard Marx

1:58 pm on Jul 4, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Better off with a generic getByClass function, but anyway..

We need a RegExp that tests for a single class word in a className (that) may contain multiple classes. For this we need:

/\b.....\b/

\b meaning "word boundary". The RegExp must be compiled on-the-fly.

The divs cllection should be cached, rather than referenced continually.
(Even better would be to narrow the search down to a particular parent container).

function whatever(sClass,sStylePropName,sValue)  
{
var elms = document.getElementsByTagName("div");
var regClass = new RegExp("\\b"+sClass+"\\b");
for(var k=-1, elm; elm=elms[++k];){
if(regClass.test(elm.className))
elm.style[sStylePropName] = sValue;
}
}

[edited by: Bernard_Marx at 2:01 pm (utc) on July 4, 2007]

Bernard Marx

2:27 pm on Jul 4, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Should add a little change because it's worth it.
The function now optionally accepts a regular expression in place of a class string. It's a simple amendment which allows you to (when you get your RE swerve going) make varied selections.

// All divs containing a class that begins with "one"
whatever(/\bone[^ ]*\b/,"color","red");

// divs containing class oneA or fourB
whatever(/\b(oneA¦fourB)\b/,"color","red");

- Doing "containg class A and B" is more complicated.

function whatever(srClass,sStylePropName,sValue) 
{
var elms = document.getElementsByTagName("div");
if(srClass.constructor!= RegExp)
srClass = new RegExp("\\b"+srClass+"\\b");
for(var k=0, elm; elm=elms[k++];){
if(srClass.test(elm.className))
elm.style[sStylePropName] = sValue;
}
}

[edited by: Bernard_Marx at 2:28 pm (utc) on July 4, 2007]

daveVk

1:32 am on Jul 5, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Looking at original posting I think all references to ".item(i)" should should be changed to "[i]" as per example below.

FROM

if (document.getElementsByTagName("div").item(i).className.indexof("something") > -1 )

TO

if (document.getElementsByTagName("div")[i].className.indexof("something") > -1 )

daveVk

2:41 am on Jul 5, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Also as some divs may not has class attribute

if ( (document.getElementsByTagName("div")[i].className)&&(document.getElementsByTagName("div")[i].className.indexof("something") > -1 ))

or taking it in smaller steps

var divEl, divEls;
divEls = document.getElementsByTagName("div");
...
divEl = divEls[i];
if ( (divEl.className)&&(divEl.className.indexof("something") > -1 )){ ...

ctoz

2:41 am on Jul 5, 2007 (gmt 0)

10+ Year Member



Many thanks: it'll take me a bit to work through these suggestions. Will post url next time :)
CT

Bernard Marx

8:17 am on Jul 5, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Also as some divs may not has class attribute

daveVK, sir. HTML elements always have a className, and it's always a string, even if it's "". So the commendable defensive programing isn't necessary.

daveVk

12:42 pm on Jul 5, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks Bernard, was not aware of that. MSDN documentation says "The property has no default value." which is a bit misleading. Assume all valid attributes have a default?

Fotiman

1:53 pm on Jul 5, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Instead of trying to re-invent the wheel, you could always use someone else's getElementsByClassName method. For example, the Yahoo UI Library [developer.yahoo.com]'s DOM Utility includes a method for doing that.

Bernard Marx

3:00 pm on Jul 5, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Assume all valid attributes have a default?

My initial answer is a definite YES. But perhaps I shouldn't be so hasty.

I have never had, or heard of any problem when dealing with standard "dot" properties. That is to say, all those element or style properties that we expect, and expect be strings. I don't know where to find specs for dot properties, or if they actually exist at all.

When it comes to get/setAttribute, IE essentially treats the methods as wrappers for dot-style access (hence problems with event handlers, and "class"). Mozilla treats attributes and dot properties as separate entities, it seems, apart from all the usual suspects.

The W3C spec for getAttribute says that a string should always be returned (even empty). There are reports of buggy null being returned in some browsers, but that may only be in the case of "non-traditional" attrbutes (and remember, the topic isn't getAttribute anyway).

I'll probably continue as always, unless given reason not to. You, on the other hand, may wish to ignore the rantings of a lunatic, and be far more careful.

Perhaps it's another reason to test with a RegExp::test(), because the method will swallow any type of argument without halting the function with an error.

daveVk

1:22 am on Jul 6, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You, on the other hand, may wish to ignore the rantings of a lunatic, and be far more careful.

No, I dont believe in blotting my code with unneeded tests. Thank for advice.

you could always use someone else's getElementsByClassName method

Yes, no use reinventing wheel, but given that it is an expensive (slow) method, need to consider if it appropriate for situation.

ctoz

2:55 am on Jul 6, 2007 (gmt 0)

10+ Year Member



Thank you also for the yahoo lead.

"learn somethi9ng new evry day even if you don't understand it..."
CT

Fotiman

3:11 pm on Jul 6, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



@DaveVk

Yes, no use reinventing wheel, but given that it is an expensive (slow) method, need to consider if it appropriate for situation.

I guess that depends on your definition of "slow". I ran a quick sample test and the getElementsByClassName method took between 15ms and 63ms during my tests, searching 202 elements. Obviously, the more items that need to be searched, the longer it will take. The YUI version allows you to also specify a root element to start searching at, which would improve performance as well.

But I agree, you do need to consider if it is appropriate for the situation.

Here's the sample test I was running for anyone who's interested:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset:utf-8">
<title></title>
<script type="text/javascript" src="http://yui.yahooapis.com/2.2.2/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript">
YAHOO.util.Event.on(window, 'load', function(){
// Add this code block 50 times
// <div class="wrapper">
// <div class="notMyClass">...</div>
// <div class="myClass">...</div>
// </div>
var container = document.getElementById('container');
var wrapper, firstDiv, lastDiv;
for (var i = 0; i < 50; i++) {
wrapper = document.createElement("div");
firstDiv = document.createElement("div");
lastDiv = document.createElement("div");
firstDiv.appendChild(document.createTextNode(i + ".1"));
lastDiv.appendChild(document.createTextNode(i + ".2"));
YAHOO.util.Dom.addClass(wrapper, 'wrapper');
YAHOO.util.Dom.addClass(firstDiv, 'notMyClass');
YAHOO.util.Dom.addClass(lastDiv, 'myClass');
wrapper.appendChild(firstDiv);
wrapper.appendChild(lastDiv);
container.appendChild(wrapper);
}
// Record the start time, get the elements by classname, record the stop time
var start, stop, myList;
start = new Date();
myList = YAHOO.util.Dom.getElementsByClassName('myClass', 'div');
stop = new Date();
// Display how long it took
alert("Total time to find " + myList.length + " items: " + (start.getTime() - stop.getTime()) + " ms");
});
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>