admin管理员组

文章数量:1279115

I have the following table being rendered in my browser. It's generated from the server side.

<table id="tblQuestions" class="tblQuestionsContainer" border="0">
    <tr>
        <td id="1" class="tdQuestion">Are u an indian citizen ?</td>
    </tr><tr>
        <td><table id="answer-1" border="0">
            <tr>
                <td><input id="answer-1_0" type="radio" name="answer-1" value="1" /><label for="answer-1_0">Yes</label></td><td><input id="answer-1_1" type="radio" name="answer-1" value="0" /><label for="answer-1_1">No</label></td>
            </tr>
        </table></td>
    </tr><tr>
        <td id="2" class="tdQuestion">Do you have a passport ?</td>
    </tr><tr>
        <td><table id="answer-2" border="0">
            <tr>
                <td><input id="answer-2_0" type="radio" name="answer-2" value="1" /><label for="answer-2_0">Yes</label></td><td><input id="answer-2_1" type="radio" name="answer-2" value="0" /><label for="answer-2_1">No</label></td>
            </tr>
        </table></td>
    </tr>
</table>

Now I am using the following code in my JavaScript to validate the radio button's checked state.

 var tblQuestionBoard=document.getElementById("tblQuestions");
  tblAnswer = tblQuestionBoard.rows[1].childNodes[0].childNodes[0]

Now tblAnswer should be an object having the Table with id "answer-1"

In IE, I am getting it. But in Mozilla and rest of the browsers I am getting it as undefined.

How to solve this?

I have the following table being rendered in my browser. It's generated from the server side.

<table id="tblQuestions" class="tblQuestionsContainer" border="0">
    <tr>
        <td id="1" class="tdQuestion">Are u an indian citizen ?</td>
    </tr><tr>
        <td><table id="answer-1" border="0">
            <tr>
                <td><input id="answer-1_0" type="radio" name="answer-1" value="1" /><label for="answer-1_0">Yes</label></td><td><input id="answer-1_1" type="radio" name="answer-1" value="0" /><label for="answer-1_1">No</label></td>
            </tr>
        </table></td>
    </tr><tr>
        <td id="2" class="tdQuestion">Do you have a passport ?</td>
    </tr><tr>
        <td><table id="answer-2" border="0">
            <tr>
                <td><input id="answer-2_0" type="radio" name="answer-2" value="1" /><label for="answer-2_0">Yes</label></td><td><input id="answer-2_1" type="radio" name="answer-2" value="0" /><label for="answer-2_1">No</label></td>
            </tr>
        </table></td>
    </tr>
</table>

Now I am using the following code in my JavaScript to validate the radio button's checked state.

 var tblQuestionBoard=document.getElementById("tblQuestions");
  tblAnswer = tblQuestionBoard.rows[1].childNodes[0].childNodes[0]

Now tblAnswer should be an object having the Table with id "answer-1"

In IE, I am getting it. But in Mozilla and rest of the browsers I am getting it as undefined.

How to solve this?

Share Improve this question edited May 28, 2009 at 23:01 Russ Cam 126k34 gold badges210 silver badges274 bronze badges asked May 28, 2009 at 11:49 ShyjuShyju 219k106 gold badges419 silver badges498 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 9

It's because you're using childNodes and whitespaces in the DOM are considered to be text nodes by Firefox et. al but not IE

See this answer for an explanation

My suggestions

1.Set up some wrapper functions that ignore any nodeType other than 1 (ELEMENT_NODE) to do DOM traversing. Something like

function child(elem, index) {
    // if index is not supplied, default is 1 
    // you might be more fortable making this 0-based
    // in which case change i initial assignment value to 0 too
    index = index || 1; 
    // get first child element node of elem
    elem = (elem.firstChild && elem.firstChild.nodeType != 1) ?
               next(elem.firstChild) :
               elem.firstChild; 
    // use the index to move to nth-child element node             
    for(var i=1; i < index;i++) {
        (function() {     
            return elem = next(elem);         
        })();        
    }
    return elem;
}

function next(elem) {
    do {
        elem = elem.nextSibling;
    } while (elem && elem.nodeType != 1);
return elem;                
}

and use like so - Working Demo - (Code at the bottom of the answer for reference)

<table id="myTable">
    <thead>
        ...
    </thead>
    <tbody>
        ...
    </tbody>
</table>

<script type="text/javascript">
    child(document.getElementById('myTable'), 2); // will get the tbody
</script>

2.Use getElementbyId(), getElementsByTagName() or getElementsByName() instead of relying on position in the DOM

3.Use a JavaScript library that abstracts away browser differences (jQuery es highly remended)

The Demo Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript">
    window.onload = function() {    
       document.getElementById('getCellContents').onclick = getCellContents;    
    }

    function child(elem, index) {
        index = index || 1; 
        elem = (elem.firstChild && elem.firstChild.nodeType != 1) ?
                   next(elem.firstChild) :
                   elem.firstChild;            
        for(var i=1; i < index;i++) {
            (function() {    
                return elem = next(elem);         
            })();        
        }
        return elem;
    }

    function next(elem) {
        do {
            elem = elem.nextSibling;
        } while (elem && elem.nodeType != 1);
    return elem;                
    }

    function getCellContents() {
        var row = parseInt(document.getElementById('row').value, 10);
        var column = parseInt(document.getElementById('column').value, 10);
        var result;
        var color;
        var table = document.getElementById('table');
        var cells = table.getElementsByTagName('td');
        for (var i= 0; i < cells.length; i++) {
            (function() {
                cells[i].bgColor = '#ffffff';
            })();
        }

        if (row && column) {
            var tbody = child(table , 2);
            var selectedRow = (row <= tbody.getElementsByTagName("tr").length)? child(tbody, row): null;
            var selectedCell = (selectedRow && column <= selectedRow.getElementsByTagName("td").length)? child(selectedRow, column): null;  

            if (selectedRow && selectedCell) {
                selectedCell.bgColor = '#00ff00';
                result = selectedCell.innerHTML;
                color = '#b7b7b7';
            }
            else {
                result = 'Cell does not exist';
                color = '#ff0000';
            }                                           
        }
        else {
            result = 'You must provide numeric arguments for Row and Column Number';
            color = '#ff0000';
        }       
        var results = document.getElementById('results');
        results.innerHTML = result;
        results.style.color = color;
    }


</script>
<title>DOM Traversal</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css">
body {
    font-family: Verdana, Helvetica, Arial;
    font-size: 0.8em;
}
h2 {
    text-align:center;
}
table { 
    border: 1px solid #000;
    border-collapse: collapse;
}   
th, td { 
    border: 1px solid #000; 
    padding: 2px; 
}
fieldset {
    border: 0;
}
label {
    display: block;
    width: 120px;
    text-align: right;
    float: left;
    padding-right: 10px;
    margin: 5px 0;
}
input {
    margin: 5px 0;
}

input.text {
    padding: 0 0 0 3px;
    width: 172px;
}

input.button {
    margin: 15px 0 0 130px;
}
span {
    font-weight: bold;
    color: #b7b7b7;
}
</style>
</head>
<body>

<h2>Example to demonstrate use of JavaScript DOM traversing wrapper functions</h2>
<div style="margin: 0 auto; width: 600px;">
<fieldset>
    <label for="row">Row Number:</label><input id="row" class="text" type="text" /><br/>
    <label for="column">Column Number:</label><input id="column" class="text" type="text" /><br/>
    <input id="getCellContents" type="button" class="button" value="Get Cell Contents" />
</fieldset> 

<p>Results: <span id="results"></span></p>

  <table id="table">
  <thead>
    <tr>
            <th>Column 1</th>
            <th>Column 2</th>   
        <th>Column 3</th>
        <th>Column 4</th>
        <th>Column 5</th>   
    </tr>   
  </thead>
  <tbody>
      <tr>
        <td>Banana</td>
        <td>Apple</td>
        <td>Orange</td>
        <td>Pineapple</td>
        <td>Cranberry</td>
      </tr>
      <tr>
        <td>Monkey</td>
        <td>Giraffe</td>
        <td>Elephant</td>
        <td>Tiger</td>
        <td>Snake</td>
      </tr>
      <tr>
        <td>C#</td>
        <td>Java</td>
        <td>Python</td>
        <td>Ruby</td>
        <td>Haskell</td>
      </tr>
      <tr>
        <td>France</td>
        <td>Spain</td>
        <td>Italy</td>
        <td>Germany</td>
        <td>Netherlands</td>
      </tr>
  </tbody>
  </table>
<p style="font-weight:bold;">The Code:
<pre><code>
&lt;script type="text/javascript"&gt;
window.onload = function() {    
   document.getElementById('getCellContents').onclick = getCellContents;    
}

function child(elem, index) {
    index = index || 1; 
    elem = (elem.firstChild && elem.firstChild.nodeType != 1) ?
               next(elem.firstChild) :
               elem.firstChild;                
    for(var i=1; i < index;i++) {
        (function() {   
            if(elem)  
            return elem = next(elem);         
        })();        
    }
    return elem;
}

function next(elem) {
    do {
        elem = elem.nextSibling;
    } while (elem && elem.nodeType != 1);
return elem;                
}

function getCellContents() {
    var row = parseInt(document.getElementById('row').value, 10);
    var column = parseInt(document.getElementById('column').value, 10);
    var result;
    var color;
    var table = document.getElementById('table');
    var cells = table.getElementsByTagName('td');
    for (var i= 0; i < cells.length; i++) {
        (function() {
            cells[i].bgColor = '#ffffff';
        })();
    }

    if (row && column) {
        var tbody = child(table , 2);
        var selectedRow = (row <= tbody.getElementsByTagName("tr").length)? 
                            child(tbody, row): null;
        var selectedCell = (selectedRow && column <= selectedRow.getElementsByTagName("td").length)? 
                                child(selectedRow, column): null;   

        if (selectedRow && selectedCell) {
            selectedCell.bgColor = '#00ff00';
            result = selectedCell.innerHTML;
            color = '#b7b7b7';
        }
        else {
            result = 'Cell does not exist';
            color = '#ff0000';
        }                                           
    }
    else {
        result = 'You must provide numeric arguments for Row and Column Number';
        color = '#ff0000';
    }       
    var results = document.getElementById('results');
    results.innerHTML = result;
    results.style.color = color;
}
&lt;/script&gt;
</code>
</pre>
</p>
  </div>
</body>
</html>

本文标签: JavaScriptTraversing the HTML DOM using childNodes causes errors in Non IE browsersStack Overflow