...

View Full Version : Helping refining a function to show and hide CSS classes on a page



number9dream
07-08-2006, 12:48 PM
Hi,

I have a function to show/hide elements on a page by CSS class, however I think it is probably quite inefficient and may have other problems. I'd appreciate any suggestions on how to improve the function.



function getStyleClass (className) {
for (var s = 0; s < document.styleSheets.length; s++)
{
if(document.styleSheets[s].rules)
{
for (var r = 0; r < document.styleSheets[s].rules.length; r++)
{
if (document.styleSheets[s].rules[r].selectorText == '.' + className)
{
return document.styleSheets[s].rules[r];
}
}
}
else if(document.styleSheets[s].cssRules)
{
for (var r = 0; r < document.styleSheets[s].cssRules.length; r++)
{
if (document.styleSheets[s].cssRules[r].selectorText == '.' + className)
return document.styleSheets[s].cssRules[r];
}
}
}

return null;
}
function toggleClass(className) {
if (getStyleClass(className).style.display == '')
{getStyleClass(className).style.display = 'none';}
else {getStyleClass(className).style.display = '';}
return false;
}


An example of how I'm calling this function is



<a href="#" onclick="toggleClass('help');return false;">Show/hide help</a>


This would make any element with a class of "help" disappear when clicked. Because there are more than one of these elements, I can't use IDs.

I think the getStyleClass function shouldn't need to loop through stylesheet rules in order to do what I want, and I'd also prefer to have one link which changes from show to hide depending on whether the class is shown or hidden.

Any help is greatly appreciated - my javascripting is not very good! :)

Bill Posters
07-08-2006, 01:43 PM
css

.hide {
display: none;
}

js

function toggleHelp() {

var divEls = document.getElementsByTagName('div');
for (var i=0, thisDiv; thisDiv=divEls[i]; i++) {
if (thisDiv.className.indexOf('help') != -1) {
thisDiv.className = (thisDiv.className.indexOf(' hide') != -1) ? thisDiv.className.replace(' hide','') : thisDiv.className+' hide';
}
}

}

markup

<a href="#" onclick="toggleHelp();return false;">Toggle help</a>



<div class="help"></div>

<div class="help"></div>

<div class="help"></div>

Try to ensure that the help elements which you're using js to toggle are visible by default when js is not available.
You might also consider actually using js to add the toggle links themselves.

Both of these things will help to ensure that users without js aren't stuck being unable to view the hidden help and aren't offered a toggle link which does nothing for them.

number9dream
07-08-2006, 04:04 PM
Thanks for the reply :)

Your suggestion definitely works, but I'm not sure it is ideal for my situation.

I would rather not add a new class to the CSS, since this means even users who don't or can't use the function get an un-needed class. I know it's a tiny bit of extra code, but I'd rather not do it on principle ;)

While I can use getElementsByTagName, I'd rather not, since I can't guarantee that the elements I want to hide use a particular tag. I might want to hide divs, paragraphs and lists, for example. I know I can put these inside a div, but I would then be forced to add unnecessary code to the markup.

The other thing is that there are a variety of different classes that I want to hide. Of course, that would be just a simple modification to your code which I am able to do.

Thanks again for your help! :)

Bill Posters
07-08-2006, 05:40 PM
I would rather not add a new class to the CSS, since this means even users who don't or can't use the function get an un-needed class. I know it's a tiny bit of extra code, but I'd rather not do it on principle ;)
Not wishing to add a single rule to the stylesheet really is an inconsequential reason and I'd say that you misunderstand the principles that should be influencing your development choices.
If you're making presentational changes to any document, then the guts of both the 'before' and 'after' presentational styles belong in the CSS along with the other presentation data.

If you wished to make changes to the 'hide' rule, then being presentational, you should expect to make alterations in the CSS file, not the js file.
It relates to the progressive notion of the separation of structure (markup), presentation (css) and 'behaviour' (scripting).
This aids the graceful degredation and helps to ensure that no users are unnecessarily given code which their UAs are not equipped to handle.
i.e. code for one technology does not bloat that of another.

A place for all things and all things in their place. ;)


While I can use getElementsByTagName, I'd rather not, since I can't guarantee that the elements I want to hide use a particular tag. I might want to hide divs, paragraphs and lists, for example.

js

function toggleHelp(classVar) {

var allEls = document.getElementsByTagName('*');
for (var i=0, thisEl; thisEl=allEls[i]; i++) {
if (thisEl.className.indexOf(classVar) != -1) {
thisEl.className = (thisEl.className.indexOf(' hide') != -1) ? thisEl.className.replace(' hide','') : thisEl.className+' hide';
}
}

}

markup

<a href="#" onclick="toggleHelp('help');return false;">Toggle 'help'</a>

<a href="#" onclick="toggleHelp('soup');return false;">Toggle 'soup'</a>

<a href="#" onclick="toggleHelp('cheese');return false;">Toggle 'cheese'</a>


If you find that this still doesn't meet your wants, then googling for getElementsByClass will return an array of ad-hoc functions produced to fill that gap.
Such a function could be used to target a specific className (or classNames).
I still recommend the storing of a 'hide' rule in the CSS as well as the use of the method I've shown to append and replace that className to the className of targeted elements.

number9dream
07-08-2006, 06:06 PM
Thanks for the second reply and the modifications to the script. :)

I'm not sure I understand the reason why you feel there should be a separate CSS class for the hidden state. I guess from my point of view I'm seeing the overall effect as functional rather than presentational. OK, the effect is achieved by changing a CSS property (i.e. presentation), but that seems to be just the most convenient method rather than because what I want to do is related to presentation.

My other question would be related to getElementsByTagName('*'). If this checks every tag on a page, does this not make it somewhat inefficient (especially for long pages)? I have experimented with some of the getelementsbyclass scripts out there, but I don't know enough javascript to determine which is likely to be the most efficient method.

Oh, and while I'm testing your patience (;)) I wonder if there's a way to change the link to show or hide depending on the current state? I know I can change them if I give them a particular ID or class, but this seems lke it might be overkill.

Thanks again for your help! :)

Bill Posters
07-08-2006, 06:20 PM
The current state can only be known by assessing CSS data.
Both techniques I've posted do that (as does your own, but in a more roundable way).

Yes, checking every element is not a particularly efficient method, but the custom getElementsByClass/getElementsByClassName I mentioned are likely to provide more efficient methods for targeting the elements you want.
I've not used any myself, but the more prominent ones are fairly well discussed.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum