22

I wrote a tab system using some very basic Javascript and it runs like a champ in IE 8 but, in FireFox 3 I am coming up short. The pertitent HTML is as follows:

            <div id="tabs">
                <ul class="tabs">
                    <li class="current"><a><span>News</span></a></li>
                    <li><a><span>Videos</span></a></li>
                    <li><a><span>Photos</span></a></li>
                    <li><a><span>Twitter</span></a></li>
                </ul>
            </div>

Then, on page load, I get dropped into this method:

function processTabs(TabContainer, PageContainer, Index) {
var tabContainer = document.getElementById(TabContainer);
var tabs = tabContainer.firstChild;

var tab = tabs.firstChild;
var i = 0;
.... more code }

The rest of the code does not matter at this point because it never gets called. tabContainer is set properly to reference the div with the ID tabs. Now, in Internet Explorer when I call tabContainer.firstChild the variable 'tabs' is referencing my UL and then the call var tab = tabs.firstChild; references my first LI. The problem is that when I call tabContainer.firstChild Venkman is telling me it is returning . So firefox is reading my newlines as actual children inside the div's! My UL is actually the second child in the childNodes collection!

Is there any way to fix this?

Thanks!

dparsons
  • 2,812
  • 5
  • 28
  • 44

6 Answers6

25

You should skip the TextNodes, a simple function can help you:

function getFirstChild(el){
  var firstChild = el.firstChild;
  while(firstChild != null && firstChild.nodeType == 3){ // skip TextNodes
    firstChild = firstChild.nextSibling;
  }
  return firstChild;
}

Usage:

var tabContainer = document.getElementById(TabContainer);
var tabs = getFirstChild(tabContainer);
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 3
    In the function `getFirstChild` I would check for `firstChild.nodeType != 1` instead of `firstChild.nodeType == 3` in order to skip also other node types such as comments. – Cito Dec 03 '12 at 22:15
  • This answer should be updated to the @Cito change suggested, I just encountered a developer that copied this exact code, and sure enough there was an HTML comment before the first element node that was being searched for... and thus failed. – scunliffe Apr 05 '17 at 19:19
  • @CMS why should TextNodes be skipped? because it's empty space in a dom? – Roxy'Pro Jan 11 '19 at 10:18
  • @Roxy'Pro: Yes, the blank spaces are text-nodes for more info [check this](https://medium.com/@patrickbrosset/b90e8a7cdd33) – Christian C. Salvadó Jan 15 '19 at 18:13
19

You can use node.firstElementChild to ignore leading text, or use a library like jQuery which takes care of this.

Max Shawabkeh
  • 37,799
  • 10
  • 82
  • 91
8

Use element.querySelector("*") to get the first child Element.

Demo:

var container = document.getElementById("container")

console.log(container.querySelector("*")) // <div>This is a test</div>
console.log(container.firstChild) // #text
console.log(container.childNodes[0]) // #text
<div id="container">
  <div>This is a test</div>
</div>
CoderPi
  • 12,985
  • 4
  • 34
  • 62
2

With a an eye also on efficiency, this function returns firstChild element node of el

function firstChildElement(el)
{
    el = el.firstChild;
    while (el && el.nodeType !== 1)
       el = el.nextSibling;
    return el;
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Marco Demaio
  • 33,578
  • 33
  • 128
  • 159
2

You can try

document.getElementById(TabContainer).firstElementChild;

instead of firstChild

B.Nabeih
  • 151
  • 1
  • 12
0

I would recommend anyone trying to work with the DOM in javascript to use a library like jquery. It will make your life much easier.

You could then rewrite the JS function as fallows:

function processTabs(TabContainer, PageContainer, Index) {
    var tabContainer = document.getElementById(TabContainer);

    // jquery used to find all the <li> elements
    var tabs = $(tabContainer).filter('li');

    // use the jquery get( index ) function to retrieve the first tab
    var tab = tabs.get(0);
    var i = 0;
    .... more code
}
Rouan van Dalen
  • 748
  • 4
  • 14