dynamically adding a row to a table (portability issue)

Discussion in 'Javascript' started by Scott, Dec 15, 2009.

  1. Scott

    Scott Guest

    Hi all,

    The following Javascript to dynamically add a row to a table works
    fine on IE, but I am not able to find a way to make it work on Firefox
    (v3.5.5).

    My problem is that childNodes[0].type is undefined for the <select>
    element. (So the newly added row has a default value of "United
    States" instead of "India".) I added a “case” to catch undefined & set
    selectedIndex=0, but it didn’t work.

    Any suggestions would be muchly appreciated?

    Scott. :)

    <HTML>
    <HEAD>
    <TITLE> Add dynamic rows in HTML table </TITLE>
    <SCRIPT language="javascript">
    function addRow(tableID) {
    var table = document.getElementById(tableID);
    var rowCount = table.rows.length;
    var row = table.insertRow(rowCount);
    var colCount = table.rows[0].cells.length;

    for(var i=0; i<colCount; i++) {

    var newcell = row.insertCell(i);
    newcell.innerHTML = table.rows[0].cells.innerHTML;
    switch(newcell.childNodes[0].type) {
    case "text":
    newcell.childNodes[0].value = "";
    break;
    case "checkbox":
    newcell.childNodes[0].checked = false;
    break;
    case "select-one":
    alert("This doesn't appears on Firefox!");
    newcell.childNodes[0].selectedIndex = 0;
    break;
    }
    }
    }
    </SCRIPT>
    </HEAD>
    <BODY>
    <INPUT type="button" value="Add Row" onclick="addRow('dataTable')" />
    <TABLE id="dataTable" width="350px" border="1">
    <TR>
    <TD><INPUT type="checkbox" name="chk"/></TD>
    <TD><INPUT type="text" name="txt"/></TD>
    <TD>
    <SELECT name="country">
    <OPTION value="in">India</OPTION>
    <OPTION value="de">Germany</OPTION>

    <OPTION value="fr">France</OPTION>
    <OPTION value="us" selected>United States</OPTION>
    <OPTION value="ch">Switzerland</OPTION>
    </SELECT>
    </TD>
    </TR>
    </TABLE>

    </BODY>
    </HTML>
     
    Scott, Dec 15, 2009
    #1
    1. Advertising

  2. Scott wrote:

    > The following Javascript to dynamically add a row to a table works
    > fine on IE, but I am not able to find a way to make it work on Firefox
    > (v3.5.5).


    Once you stopped thinking in terms of different browsers and start thinking
    in terms of different layout engines, you will understand a lot better what
    really happens when working with the client-side DOM.

    > My problem is that childNodes[0].type is undefined for the <select>
    > element. (So the newly added row has a default value of "United
    > States" instead of "India".) I added a “case†to catch undefined & set
    > selectedIndex=0, but it didn’t work.


    "Does not work" is a useless error description. [psf 4.11]

    <http://jibbering.com/faq/#posting>

    > Any suggestions would be muchly appreciated?


    <http://www.catb.org/~esr/faqs/smart-questions.html>

    I do not know if you appreciate any suggestion, however here is one:

    You have not considered white-space text nodes; you are most certainly
    accessing one with childNodes[0] in a Gecko-based browser, and such objects
    do not have a built-in `type' property (as a result, the value retrieved is
    `undefined' which causes your script to "not work"). MSHTML silently
    discards white-space text nodes occasionally (there really seems to be no
    pattern), while other layout engines do not. Often discussed, often
    resolved before. See above.

    Your markup also is far from being Valid, which does not bode well for your
    script code to work reliably in the first place. (Also not news here.)

    Evidently now, you have taken the fourth step in the Web development
    learning curve (DOM Scripting) before the first one (HTML); a recipe for
    disaster.

    <http://validator.w3.org/>


    PointedEars
    --
    Prototype.js was written by people who don't know javascript for people
    who don't know javascript. People who don't know javascript are not
    the best source of advice on designing systems that use javascript.
    -- Richard Cornford, cljs, <f806at$ail$1$>
     
    Thomas 'PointedEars' Lahn, Dec 15, 2009
    #2
    1. Advertising

  3. Scott

    RobG Guest

    On Dec 15, 1:55 pm, Scott <> wrote:
    > Hi all,
    >
    > The following Javascript to dynamically add a row to a table works
    > fine on IE, but I am not able to find a way to make it work on Firefox
    > (v3.5.5).
    >
    > My problem is that childNodes[0].type is undefined for the <select>
    > element.


    As Thomas said - it is likely a text node, not an element, and does
    not hav a type property.


    > (So the newly added row has a default value of "United
    > States" instead of "India".) I added a “case” to catch undefined & set
    > selectedIndex=0, but it didn’t work.


    Better to address the cause than the symptoms.


    > Any suggestions would be muchly appreciated?
    >
    > Scott. :)
    >
    > <HTML>
    > <HEAD>
    > <TITLE> Add dynamic rows in HTML table </TITLE>
    > <SCRIPT language="javascript">


    The language attribute has been deprecated long ago, type is required:

    <script type="text/javascript">

    > function addRow(tableID) {
    > var table = document.getElementById(tableID);
    > var rowCount = table.rows.length;
    > var row = table.insertRow(rowCount);


    If you want to add a new row as the last row, you can use:

    var row = table.insertRow(-1);

    <URL: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-39872903 >

    > var colCount = table.rows[0].cells.length;
    >
    > for(var i=0; i<colCount; i++) {
    >
    > var newcell = row.insertCell(i);
    > newcell.innerHTML = table.rows[0].cells.innerHTML;
    > switch(newcell.childNodes[0].type) {
    > case "text":
    > newcell.childNodes[0].value = "";
    > break;
    > case "checkbox":
    > newcell.childNodes[0].checked = false;
    > break;
    > case "select-one":
    > alert("This doesn't appears on Firefox!");
    > newcell.childNodes[0].selectedIndex = 0;
    > break;
    > }
    > }
    > }


    Consider instead cloning the row, iterating over the cells and
    updating the internals using a function that recurses over the child
    nodes, e.g.

    <script type="text/javascript">

    function addRow(tableID) {

    var table = document.getElementById(tableID),
    lastRow = table.rows[table.rows.length - 1];
    row = table.rows[0].cloneNode(true),
    cells = row.cells;

    for (var i=0, iLen=cells.length; i<iLen; i++) {
    updateCell(cells);
    }

    lastRow.parentNode.appendChild(row);
    }


    function updateCell(cell) {

    var nodes = cell.childNodes,
    node,
    nodeType;

    for (var i=0, iLen=nodes.length; i<iLen; i++) {
    node = nodes;
    nodeType = node.type;

    if (node.childNodes) {
    updateCell(node);
    }

    switch (nodeType) {

    case "text":
    node.value = "";
    break;

    case "checkbox":
    node.checked = false;
    break;

    case "select-one":
    node.selectedIndex = 0;
    break;
    }
    }
    }
    </script>
    <div>
    <input type="button" value="Add Row" onclick="addRow('dataTable')">
    </div>
    <table id="dataTable" width="350px" border="1">
    <tr>
    <td><input type="checkbox" name="chk">
    <td><input type="text" name="txt">
    <td><select name="country">
    <option value="in">India
    <option value="de">Germany
    <option value="fr">France
    <option value="us" selected>United States
    <option value="ch">Switzerland
    </select>
    </table>


    --
    Rob
     
    RobG, Dec 16, 2009
    #3
  4. Scott

    Scott Guest

    In the unlikely event that someone else is interested in this, here is
    a solution:

    Ignore whitespace nodes by applying the switch statement to ALL the
    child nodes:

    for (var j = 0; j < newcell.childNodes.length; j++)
    {
    switch (newcell.childNodes[j].type) {
    case "text":
    .....
    }

    Scott. :)
     
    Scott, Dec 16, 2009
    #4
  5. Scott wrote:

    > In the unlikely event that someone else is interested in this, here is
    > a solution:
    >
    > Ignore whitespace nodes by applying the switch statement to ALL the
    > child nodes:


    you could simply remove the whitespace after the start tag, as in

    <td><select ...>...

    Or you could simply address the SELECT element by its name, as in

    document.getElementsByName("country")[0]

    or if the SELECT element would be descendant of a FORM element like it
    should (for the form to degrade gracefully):

    document.forms[...].elements["country"]

    All of this is described in the FAQ of this newsgroup that I had referred
    you to.

    > for (var j = 0; j < newcell.childNodes.length; j++)
    > {
    > switch (newcell.childNodes[j].type) {
    > case "text":
    > .....
    > }


    What an unnecessary, inefficient piece of junk. Didn't I recommend that you
    take step 1 first?


    PointedEars
    --
    realism: HTML 4.01 Strict
    evangelism: XHTML 1.0 Strict
    madness: XHTML 1.1 as application/xhtml+xml
    -- Bjoern Hoehrmann
     
    Thomas 'PointedEars' Lahn, Dec 16, 2009
    #5
  6. Scott

    Scott Guest

    > Consider instead cloning the row, iterating over the cells and
    > updating the internals using a function that recurses over the child
    > nodes


    Even better!

    Thanks Rob.

    Scott. :)
     
    Scott, Dec 16, 2009
    #6
  7. Scott

    Scott Guest

    > What an unnecessary, inefficient piece of junk.  Didn't I recommend that you
    > take step 1 first?


    Take a pill man! Sheesh.

    Scott. :)
     
    Scott, Dec 16, 2009
    #7
  8. Scott wrote:

    >> What an unnecessary, inefficient piece of junk. Didn't I recommend that
    >> you take step 1 first?

    >
    > Take a pill man! Sheesh.


    My taking a pill will not cure your incompetence. Only your RTFM can.


    Score adjusted

    PointedEars
    --
    Prototype.js was written by people who don't know javascript for people
    who don't know javascript. People who don't know javascript are not
    the best source of advice on designing systems that use javascript.
    -- Richard Cornford, cljs, <f806at$ail$1$>
     
    Thomas 'PointedEars' Lahn, Dec 16, 2009
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. lucky
    Replies:
    0
    Views:
    516
    lucky
    Jan 12, 2005
  2. phl
    Replies:
    1
    Views:
    4,366
    Martin Jay
    Jun 8, 2006
  3. jameskuyper
    Replies:
    2
    Views:
    273
    Peter Nilsson
    May 15, 2009
  4. CBFalconer
    Replies:
    8
    Views:
    268
    James Kuyper
    May 13, 2009
  5. D
    Replies:
    0
    Views:
    223
Loading...

Share This Page