getElementByClass Display:None

Am I using this correctly? For some reason it isn’t working.

document.getElementByClass('details').style.display='none';

I’m using getElementByID to show DIVs inline-block, but I want a universal button to hide whichever DIV is displaying, as well.

Thanks :slight_smile:

There isn’t a getElementsByClass function.

However, you can make one pretty easily.

Give me a second and I’ll give you one you can use.

Here we go:


/// Returns an array of all elements including and within the element that this function is called from.
/// If you want only elements with a certain classname and certain tagname, you can supply the optional tagname.
/// @param name - The name of the class to search for (case-sensitive).
/// @param tagname - The tag name of the elements you want to get. (optional, case-insensitive).
Element.prototype.getElementsByClass = function(name, tagname) {	
	var elements = new Array();
	
	if(this == document)
		var node = document.body;
	else
		var node = this;
	
	while(node.tagName != 'HTML') {
		if(node.className) {
			var classes = node.className.split(' ');
		
			for(var i=0; i < classes.length; i++)
				if(classes[i] == name) {
					if(!tagname || tagname.toLowerCase() == node.tagName.toLowerCase())
						elements.push(node);
					break;
				}
		}
		if(node.hasChildNodes())
			node = node.firstChild;
		else if(node.nextSibling != null)
			node = node.nextSibling;
		else if(node.parentNode != this && node.parentNode.nextSibling != null)
			node = node.parentNode.nextSibling;
		else
			break;
	}
	
	return elements;
}

Document.prototype.getElementsByClass = Element.prototype.getElementsByClass;

You can check out an example of it in action here: http://www.arwebdesign.net/tests/byclass.html

I added an optional tag name since you said you only wanted divs. If you notice, it is prototyped for both Element and Document, which means you can use it like this:


document.getElementsByClass("bob");
document.getElementById("someid").getElementsByClass("bob");

Good luck, let me know if there are any problems.

Wow, thanks. I didn’t realize it’d be that much code.

Not that I don’t appreciate the work you did, but if there is no such function is it possible/shorter to write one that hides any DIV with an ID in the format “details#” where # is any number?

Also, all I’m seeing on your example is the following.

bob1

bob2

bob3

bob4

bob5

bob8

bob9

Test created by Christian Snodgrass of Azure Ronin Web Design
Safari 4 b.

You could try it with jQuery


$([id^=details]).hide();

The ^= matches attributes that start with the given value.
http://docs.jquery.com/Selectors/attributeStartsWith#attributevalue

The real trick though is how to achieve this without jQuery, using a small amount of code.

Hmm. I don’t have a problem using jQuery but as of now I’m not using it, so I’d have to include all the javascript files, right?

You can link to http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js which people have quite likely already cached from visiting other pages.


<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"> </script>
<script type="text/javascript">
$(function () {
    $([id^=details]).hide();
}
</script>

There is a getElementsByClassName function in Firefox 3.*

Also instead, I would use the Selector API for those browsers that support it.
Internet Explorer 8, [URL=“http://my.opera.com/core/blog/selectors-api”]Opera, Safari 3.1, & Firefox 3.1

I second logic_earth - I’d use querySelector if it’s available and if not just declare a backup method but firstly don’t make it a method of the Element prototype because that simply wouldn’t work in MS DOM as there is no Element or HTMLElement object.

@SoulScratch Oh, you’re right. I think I knew that, but just forgot about it when I was getting “creative”. To fix this, you would just add another parameter to the function (the object to start at), and change any reference to “this” to the new parameter. I’ll update my example function because I don’t have not-cross-browser compliant code lingering.

@geiger Yeah, the demo is just outputting the ids of the elements that it selected to make sure it’s correct.

If you wanted to use older Javascript, the only way to make sure you get all of them is to transverse the tree structure (which is the while loop portion of the code) and manually check the IDs (something like if(substr(node.id,0,7) == ‘details’) // do something).

The Selector method is the way to go though if you thing a decent portion of your members will have a relatively up-to-date browser, though be sure to implement a back-up method like what we discussed.

EDIT: I modified the function so it’s now cross-browser compliant.

Another method you could use to make it shorter is something like:


if(!document.getElementsByTagName)
    return;

var divs = document.getElementsByTagName("DIV");

for(var i=0; i < divs.length; i++)
    if(substr(divs[i].id, 0, 7) == 'details')
        divs[i].style.display = "none";

That will get all elements with the tag name of “div” and then if they are details#, it’ll hide it by setting display:none.

Hope that helps.

If you know that you’re going to be dealing with only a cerrtain element, you can use getElementsByTagName quite effectively. Especially if you know that they’re contained within some other kind of structure.


var container = document.getElementById('bobContainer');
var els = container.getElementsByTagName('div');
var i;
for (i = 0; i < els.length; i += 1) {
    if (els[i].id.match(/^bob/)) {
        els[i].style.display = 'none';
    }
}

I really don’t know Javascript, so I don’t understand some of what you all are talking about. I do think still, however, that I’m going about things the wrong way.

I decided to go ahead and admit access to those who are helping in this thread.
http://www.myhybridcar.com/fueleconomy/view_car.php?cid=108
Username: sitepoint
Password: temporary

Click on a tank with a + sign. You’ll note a DIV and the table disappear, and a DIV and the appropriate tank DIV appear. The part I’m working on now is the Back to Tank List link. I need to restore the original DIV/table and hide the most recent DIV/DIV.

Ok, as of now you’re relying on adding a hash to the current page, setting divs to inline-block as opposed to block ( the native display method ), and inline JS which could be vastly improved.

Do this right and it’ll work out fine, the first step is to remove all that inline JS and set the ID to the corresponding info div that will popup.

Step #1: Remove inline JS and add IDs to the table rows in table#data_table, as well as remove the “date” class from the table cells ( and I know you’re relying on them for CSS but thats ok we’ll modify that as well ).

Example:

<tr onclick="window.location='#'; document.getElementById('data_table').style.display='none'; document.getElementById('data_heading_left').style.display='none'; document.getElementById('data_details').style.display='inline-block'; document.getElementById('details1953').style.display='inline-block'; " class="data">
				<td class="data ismore">+</td>
				<td class="data">February 26, 2006</td>
				<td class="data">201</td>
				<td class="data">6.3</td>
				<td class="data">32.1</td>
			</tr>

Becomes

<tr id="row-details1953" class="data">
				<td class="ismore">+</td>
				<td>February 26, 2006</td>
				<td>201</td>
				<td>6.3</td>
				<td>32.1</td>
			</tr>

Step #2: Modify the two css rules you have for .data, .data_do as such:

.data_do, tr.data, tr.data td {
    border-left:1px solid #CCCCCC;
    cursor:pointer;
    font-size:11px;
    padding:5px 0 5px 7px;
}


Also, we’ll need to modify .heading_option because we’re changing your inline-blocks to regular block ( IE doesnt support inline-block on anything but native inline elements ):

.heading_option {
    margin:-15px 0 0;
}

Step #3: Place this JS right before the </body> end tag:

(function() {
    var toggle = function( el, str ) {
	    if (!str ) {
		el.style.display = ( el.style.display === '' ) ? 'none' : '';
	    } else {
		el.style.display = str;
	    }
	},
	getId = function( id ) { return document.getElementById(id) },
	table = getId('data_table'),
	backTo = getId('data_details').getElementsByTagName('a')[0],
	currentlyOpen,
	getElementsByClassName = 
	    document.getElementsByClassName ? function (class_name, scope) {
		    return (scope || document).getElementsByClassName(class_name);
	    } 
	    : document.querySelectorAll ? function (class_name, scope) {
		    return (scope || document).querySelectorAll("." + class_name);
	    } 
	    : document.evaluate ? function (class_name, scope) {
		    var n,
			    r = [],
			    x = document.evaluate("descendant::*[contains(concat(' ', @class, ' '), ' " + class_name + " ')]",
				    scope || document, null, 5, null);
		    while (n = x.iterateNext()) {
			    r.push(n);
		    }
		    return r;
	    } 
	    : function (class_name, scope) {
		    scope = scope || document;
		    var nL = scope.all || scope.getElementsByTagName("*"),
			    r = [];
		    for (var i = 0, n; n = nL[i]; ++i) {
			    if (n.className && (' ' + n.className + ' ').indexOf(' ' + class_name + ' ') != -1) {
				    r.push(n);
			    }
		    }
		    return r;
	    };

    
    if (!table || !backTo) { return; }

    var rows = getElementsByClassName('data', table);

    if (!rows.length){return;}

    for ( var i = 0, l = rows.length, row; i < l; ++i ) {
	row = rows[i];
	row.onclick = function() {
	    var corresponding = this.id.slice(4);
	    currentlyOpen = getId(corresponding);
	    if (!currentlyOpen ) { return false; }
	    toggle( getId('data_table') );
	    toggle( getId('data_heading_left') );
	    toggle( getId('data_details'), 'block' );
	    toggle( currentlyOpen, 'block' );
	    return false;
	}
    }

    backTo.onclick = function() {
	toggle( getId('data_table') );
	toggle( getId('data_details') );
	toggle( getId('data_heading_left') );
	toggle( currentlyOpen );
	return false;
    }
    
})();

Note #1 - I did use a getElementsByClass fn that’s more optimized for newer browsers
Note #2 - For table rows which did not have a corresponding details div ( the ones without plus signs ) clicking does nothing, while currently your page hides the initial table and attempts to show a div. I’m guessing this is because your code is in a php loop, this won’t be a problem as my JS does the logic to check if theres a corresponding div.

Here’s my local page on a server, so you can see the changes for yourself:
http://inimino.org/~amthx/table.html

Let me know if you have any issues. I only tested the JS if it’s added to this page alone, though it shouldn’t break if its added globally.

Hrmm. Thanks, but it doesn’t seem to be working very well.
http://www.myhybridcar.com/fueleconomy/view_car.php?cid=108

Could you be more specific? No idea what you’re referring to and I see nothing wrong in Fx3 with the JS behavior nor CSS style, it’s functioning exactly as I thought it should.

Okay.

.heading_option no longer displays in the same way, but that’s minor.
Clicking on a row initially works.
Clicking “back” makes all the columns collapse, ignoring their widths. The tank details also do not disappear; they’re at the bottom of the table.
Clicking a row afterwards makes the columns expand to width instead of the row’s expected onclick function.

Odd, I’m not experiencing the “ignoring their widths” issue at all. The tank details disappear for me in that they’re not visible.

Where are you defining the widths? In the initial row’s width attribute for table cell elements?

What browser are you using? And are you getting any JS errors?

Did you ctrl+f5 for a hard refresh so the css is updated?

Edit: This is how it functions in my browser: http://inimino.org/~amthx/js/js.html

I suspect it may be a JS error causing it to not function correctly or something along those lines…

I’m using Safari 4b Mac, and had similar width problems on Safari 3 Mac. I am referring to the initial width attribute. The problem occurs when they are seemingly ignored and the next cell begins immediately after the previous cell’s contents end; there’s whitespace at the right of each row.

Thanks for the screencast—works for you!

I cleared my cache. No difference.

Hey well this is weird. It works when I’m logged out but it breaks again when I’m logged in! Feel free to register to test. (link on the forums page)

It appears this is left over when you’re logged in:

<a href="#" [B]onclick="document.getElementById('data_table').style.display='inline-block'; document.getElementById('data_heading_left').style.display='inline-block'; document.getElementById('data_details').style.display='none'; document.getElementByClass('details').style.display='none';[/B]">&lsaquo; Back to Tank List</a>

This will need to be removed, as there are conflicting onclicks :wink: Good job detecting it was the login part.

And the reason the widths messed up was because you’re setting an element which natively acts as a block level but is a table to inline-block, so it loses certain features and apparently column widths are one of them ( from the old JS ).