18-08-2009

Counting childnodes with JavaScript – The Whitespace Incident

Update: Since this is by far the most visited page on this blog (Google likes it I guess) I figured I’d write a short summary. I guess you found this page searching for a way to properly count html elements with JavaScript after getting different results in different browsers in which case I hope you’ll find what you’re looking for here.

The problem I encountered was that IE and Firefox behaved differently when counting child elements/nodes, where IE returned the expected value. Turns out IE is wrong, but because it skips whitespace (linebreak, tab, space…) while counting, the problem appears to be related to other browsers. Anyway, in order to get the expected value in other browsers too the script has to run a check on whether or not each child node belongs to nodetype 3. There are a whole bunch of different nodetypes, 3 being whitespace.

The following code example should give you something to go by:

var kids;
var realKids;
var parent;
var i = 0;
function countTheKids(){
	realKids = 0;
	parent = document.getElementById("parent");
	kids = parent.childNodes.length;
	while(i < kids){
		if(parent.childNodes[i].nodeType != 3){
			realKids++;
		}
		i++;
	}
	return realKids;
}

Feel free to drop a comment, or take a look at the original post below :)

I’m currently working on a project where I get to explore the world of JavaScript, which means I keep running into all kinds of new problems related to compatibility issues between the different web browsers. HTML and CSS: Been there, done that, you name it, I fix it. JavaScript however…

Anyway, after a day of battling my company’s CMS, implementing custom scripts and markup, and eventually getting everything running the way I wanted – checking only in IE as I went along (don’t ask) – I gave my newborn creation a go in Firefox. Epic fail. Nothing really worked. At all. But after a while I finally figured out that there was a problem related to how specific elements within a page are counted.

Now, consider the following code:

<div id="parent">
	<div class="child">This contains a lot of other divs</div>
	<div class="child">So does this one.</div>
	<div class="child">And this.</div>
	<div class="child">Your guess.</div>
</div>

This is a very simplified version of my original code, but a valid example nonetheless.

XML, DOM and whatnot, even if you’ve never heard of these terms you’ll probably notice that the parent div has four children. Or so it seems. Anyway, to count the number of child elements I naturally assumed the following JavaScript code would get the job done:

var kids;
function countTheKids(){
	kids = document.getElementById("parent").childNodes.length;
	return kids;
}

And it sort of did. Internet Explorer returns a value of 4. Firefox, Opera, and who knows which other browsers will tell you that there are in fact nine kids running around, which raises the question: Where the hell are the remaining five? Let’s ask the DOM…

It turns out that ghosts are also children. Or nodes. And in this case, the ghosts’ true shape is whitespace. Line break, space, tab, all those things that are neatly ignored in most programming languages. Thus we wind up with 9 child nodes, living and dead.

But in my case it was critical to get the number of proper child elements, and I suddenly found myself in the middle of a headscratching routine. So, why didn’t I just write a small function to get the number of elements with class=”child”? you ask. Because I couldn’t. The CMS I’m using has a habit of adding bits and pieces to my code, and in this case class=”child” would be transformed into something like class=”child 341125″. Bummer. The good thing is, the function I wrote to analyse the child nodes isn’t exactly rocket science either:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var kids;
var realKids;
var parent;
var i = 0;
function countTheKids(){
	realKids = 0;
	parent = document.getElementById("parent");
	kids = parent.childNodes.length;
	while(i < kids){
		if(parent.childNodes[i].nodeType != 3){
			realKids++;
		}
		i++;
	}
	return realKids;
}

The magic happens at line 10. It turns out that all markup nodes are defined as a nodetype. Whitespace, every one of them, is type 3. So by adding up all nodes that are not type 3 I find the number of proper child elements, and my troubles are over. This solution is not the most elegant one, but it works and solved my problem, so there you have it. Go count those kids!

4 kommentarer til Counting childnodes with JavaScript – The Whitespace Incident

  1. rav sier:

    thanks for this, i’ve been searching around for an explanation of how firefox handles the dom tree.

    however – i get a different error, which is that firefox somehow outputs <! at the end of my list.

    so im wondering, if nodetype 3 relates to whitespace, what about line breaks, and newlines etc?

  2. Daniel sier:

    @rav Nodetype 3 actually relates to all kinds of text, that is DOM elements that are not enclosed with tags. Firefox correctly interprets whitespace, line breaks and newlines as text elements, which sort of makes sense if you think about it. The first example on this page http://www.oracle.com/technology/pub/articles/wang-whitespace.html illustrates it quite well.

    About the <!, I’m not quite sure if I understand what you mean. Is it a normal html comment tag, or something that Firefox adds to the mix?

  3. Codventure sier:

    I have define and define 8 tabs in the table and when i am counting childNodes from javascript document.getElementById(‘tabs’).childNodes
    it gives me only 1 tab, but there are 8 tabs.
    How to do?
    Codventure

  4. Daniel sier:

    @Codeventure
    Your code will return all elements contained within the element with id=”tabs”. If you give every tab element id=”tabs” your code will fail, firstly because there can be only be one instance of any one id in a web page, secondly because the code will count every element contained within the first (or last, not quite sure at the moment) element with id=”tabs”.

    Since you haven’t linked to a code example I can’t really give you any further assistance.

Legg igjen et svar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *

*

Du kan bruke disse HTML-kodene og -egenskapene: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">