Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 6 of 6
  1. #1
    New to the CF scene
    Join Date
    Jul 2006
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Helping refining a function to show and hide CSS classes on a page

    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.

    Code:
    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

    Code:
    <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!

  • #2
    Senior Coder
    Join Date
    Feb 2003
    Posts
    1,665
    Thanks
    0
    Thanked 27 Times in 25 Posts
    css
    Code:
    .hide {
    	display: none;
    }
    js
    Code:
    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
    Code:
    <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.
    Last edited by Bill Posters; 07-08-2006 at 02:09 PM.

  • #3
    New to the CF scene
    Join Date
    Jul 2006
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts
    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!

  • #4
    Senior Coder
    Join Date
    Feb 2003
    Posts
    1,665
    Thanks
    0
    Thanked 27 Times in 25 Posts
    Quote Originally Posted by number9dream
    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
    Code:
    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
    Code:
    <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.
    Last edited by Bill Posters; 07-08-2006 at 05:49 PM.

  • #5
    New to the CF scene
    Join Date
    Jul 2006
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts
    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!
    Last edited by number9dream; 07-08-2006 at 06:09 PM.

  • #6
    Senior Coder
    Join Date
    Feb 2003
    Posts
    1,665
    Thanks
    0
    Thanked 27 Times in 25 Posts
    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.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •