cloneNode/appendChild and children

Discussion in 'Javascript' started by Olorin, Apr 30, 2007.

  1. Olorin

    Olorin Guest

    Hello everyone. I'm playing around with some AJAX-ish stuff and
    encountered some problem in the JS side of the universe. Maybe someone
    here can suggest an alternative that works.

    I have developed a simple ASP.NET application with a web page that
    should display a list of users. This list page is designed to start
    with an empty table (with columns defined), and, onload, send an
    XmlHttp request to a server component (a.k.a. ListServer). This
    ListServer is currently simulating a long-running operation. So, it
    sleeps for 3 seconds, and then grabs a list of 4 users from an xml
    file. It applies an xsl transformation and returns the result.

    The xslt is designed to take the xml data and convert it to a
    <ListChunk> root element containing a <tr> for each user in the XML
    data. Each row contains 4 columns (Id, Login, Password, Name). The
    javascript in the list page grabs the responseXML from the XmlHttp
    object and should, for each <tr> in it, create a copy of the row
    coming from the server and adding it to the list on the client.

    I actually got all that to work quite fine. The js snipplet dealing
    with copying the row coming from the server and adding it to the table
    on the client is:

    (listChunk is the responsseXML fromt he XmlHttp object, and tableBody
    is the body of the table in the page)

    var userRows = listChunk.getElementsByTagName("tr");
    if(userRows==null || userRows.length==0)
    {
    EndAsyncLoading();
    return;
    }
    for(var rowIndex=0; rowIndex<userRows.length; rowIndex++)
    {
    var serverRow = userRows[rowIndex];
    var clientRow = tableBody.insertRow(-1);

    var serverCells = serverRow.getElementsByTagName("td");
    for(var cellIndex=0; cellIndex<serverCells.length; cellIndex+
    +)
    {
    var serverCell = serverCells[cellIndex];
    var clientCell = serverCell.cloneNode(true);
    clientRow.appendChild(clientCell);
    }
    }

    As you can see, it's a call to insertRow followed by a call to
    cloneNode and appendChild for each cell int he row.

    Today I modified the xsl on the server to make the Id and Login
    columns links. The odd thing is that the table rows added to the table
    on the page include the links in the first two cells, but the browser
    does not let me click on them.

    Even better.. if I save the resulting page locally, and then re-open
    it in the same browser, the links are recognized as such and
    clickable.

    I'm working in Firefox 2 for now, but would certainly like to find a
    solution that works at least in FF2 and IE7 (although IE7 is still
    yelling at me for using appendChild /sigh)

    Thanks in advance,
    F.O.R.
     
    Olorin, Apr 30, 2007
    #1
    1. Advertising

  2. Olorin

    RobG Guest

    On May 1, 8:27 am, Olorin <> wrote:
    > Hello everyone. I'm playing around with some AJAX-ish stuff and
    > encountered some problem in the JS side of the universe. Maybe someone
    > here can suggest an alternative that works.
    >
    > I have developed a simple ASP.NET application with a web page that
    > should display a list of users. This list page is designed to start
    > with an empty table (with columns defined), and, onload, send an
    > XmlHttp request to a server component (a.k.a. ListServer). This
    > ListServer is currently simulating a long-running operation. So, it
    > sleeps for 3 seconds, and then grabs a list of 4 users from an xml
    > file. It applies an xsl transformation and returns the result.
    >
    > The xslt is designed to take the xml data and convert it to a
    > <ListChunk> root element containing a <tr> for each user in the XML
    > data.


    It seems rather pointless to use XSLT to convert XML to XML. Why not
    convert it to HTML and save yourself a lot of trouble?

    > Each row contains 4 columns (Id, Login, Password, Name). The
    > javascript in the list page grabs the responseXML from the XmlHttp
    > object and should, for each <tr> in it, create a copy of the row
    > coming from the server and adding it to the list on the client.
    >
    > I actually got all that to work quite fine. The js snipplet dealing
    > with copying the row coming from the server and adding it to the table
    > on the client is:
    >
    > (listChunk is the responsseXML fromt he XmlHttp object, and tableBody
    > is the body of the table in the page)
    >
    > var userRows = listChunk.getElementsByTagName("tr");
    > if(userRows==null || userRows.length==0)


    In what circumstance will userRows be null?

    If supported, getElementsByTagName returns a NodeList object, always.
    If it's not, attempting listChunk.getElementsByTagName("tr") will
    cause your script to fail before the test is reached.


    > {
    > EndAsyncLoading();
    > return;
    > }
    > for(var rowIndex=0; rowIndex<userRows.length; rowIndex++)
    > {
    > var serverRow = userRows[rowIndex];
    > var clientRow = tableBody.insertRow(-1);
    >
    > var serverCells = serverRow.getElementsByTagName("td");
    > for(var cellIndex=0; cellIndex<serverCells.length; cellIndex+
    > +)
    > {
    > var serverCell = serverCells[cellIndex];
    > var clientCell = serverCell.cloneNode(true);
    > clientRow.appendChild(clientCell);
    > }
    > }
    >
    > As you can see, it's a call to insertRow followed by a call to
    > cloneNode and appendChild for each cell int he row.


    Why not send HTML instead of XML and just append the rows to the table
    (insert the HTML as the innerHTML of a div to convert it to a DOM
    object, just wrap the trs in table tags)? You could also just grab
    the tbody and append it to the current table or replace the current
    tbody - done in one go.


    > Today I modified the xsl on the server to make the Id and Login
    > columns links. The odd thing is that the table rows added to the table
    > on the page include the links in the first two cells, but the browser
    > does not let me click on them.


    Without seeing the initial XML and the resulting markup I can only
    guess.

    > Even better.. if I save the resulting page locally, and then re-open
    > it in the same browser, the links are recognized as such and
    > clickable.


    Probably because you are sending XML, not HTML. Saving it locally as
    HTML then loading it back in changes how the parser interprets the
    markup.


    > I'm working in Firefox 2 for now, but would certainly like to find a
    > solution that works at least in FF2 and IE7 (although IE7 is still
    > yelling at me for using appendChild /sigh)


    Do not feed XML to IE.


    --
    Rob
     
    RobG, May 1, 2007
    #2
    1. Advertising

  3. Olorin

    Olorin Guest

    On Apr 30, 9:53 pm, RobG <> wrote:
    >
    > It seems rather pointless to use XSLT to convert XML to XML. Why not
    > convert it to HTML and save yourself a lot of trouble?


    Possibly, but this is a simple mock-up, and I was following samples I
    found online.
    I was interested in learning a bit about the server-side application
    of transforms anyway.

    > In what circumstance will userRows be null?


    When, for instance, the server has finished sending all users.
    Right now (again, this is a mock), the server will send
    4 user-rows at the time, for a maximum of 4 times.
    When it reaches the end of the simulkated users, it leaves
    the response stream clear.

    > Why not send HTML instead of XML and just append the rows to the table
    > (insert the HTML as the innerHTML of a div to convert it to a DOM
    > object, just wrap the trs in table tags)? You could also just grab
    > the tbody and append it to the current table or replace the current
    > tbody - done in one go.


    I actually tried to switch the xsl transformation output from xml to
    html, just to see
    if it made any difference, but it didn't.
    I've been reading around and it seems that, indeed, cloneNode does not
    copy
    all attributes and/or event handlers (although in my case the href
    attribute is cloned),
    and that simply adding a node to an [x]html document is not enough.
    See for instance this article: http://alistapart.com/articles/crossbrowserscripting
    It focuses on importNode, rather than cloning and appending (like I am
    doing), but the
    problem seem to be the same.

    > Without seeing the initial XML and the resulting markup I can only
    > guess.


    The source of users is an xml file as follows: (I'll show you a single
    user, but there are 4 in the actual file)
    <?xml version="1.0" encoding="UTF-8"?>
    <ListPage>
    <User id="1">
    <Login>fred</Login>
    <Password>Wilma</Password>
    <FirstName>Fred</FirstName>
    <LastName>Flinstone</LastName>
    </User>
    </ListPage>

    The xslt, with the first 2 columns set to be links:
    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
    Transform">
    <xsl:eek:utput method="xml" encoding="UTF-8" indent="yes" omit-xml-
    declaration="no" standalone="yes" />
    <xsl:strip-space elements="*" />
    <xsl:template match="/">
    <ListChunk>
    <xsl:for-each select="ListPage/User">
    <tr>
    <td>
    <a href="http://www.google.com"><xsl:value-of
    select="@id" /></a>
    </td>
    <td>
    <a href="http://www.google.com"><xsl:value-of
    select="Login" /></a>
    </td>
    <td>
    <xsl:value-of select="Password" />
    </td>
    <td>
    <xsl:value-of select="FirstName" />
    </td>
    <td>
    <xsl:value-of select="LastName" />
    </td>
    </tr>
    </xsl:for-each>
    </ListChunk>
    </xsl:template>
    </xsl:stylesheet>

    Using firebug, I've been checking what gets sent by the server to the
    client, and it seems to be:
    <ListChunk>
    <tr>
    <td><a href="http://www.google.com">1</a></td>
    <td><a href="http://www.google.com">fred</a></td>
    <td>Wilma</td>
    <td>Fred</td>
    <td>Flinstone</td>
    </tr>
    </ListChunk>


    As I said, changing the output method of the transform from xml to
    html didn't seem to make any difference.

    I can share the whole thing if needed (including the javascript that
    kicks off the request on page load, etc etc), but it really seem to me
    that there's something going on with the cloneNode/appendChild
    sequence.
    In the article I mentioned above, A. Holdener explains that

    That might be the reason why the links are not being treated as links
    (but reloading the page from a local copy makes them act like proper
    links).
    Or maybe not, maybe it's totally unrelated and I'm missing something
    else.

    > Do not feed XML to IE.


    ....so what's the recommended cross-browser 'closest-to-standard-
    compliance' approach to take for something like this ?

    Thanks for reading and answering,
    F.O.R.
     
    Olorin, May 1, 2007
    #3
  4. Olorin

    RobG Guest

    On May 1, 10:05 pm, Olorin <> wrote:
    > On Apr 30, 9:53 pm, RobG <> wrote:
    >
    >
    >
    > > It seems rather pointless to use XSLT to convert XML to XML. Why not
    > > convert it to HTML and save yourself a lot of trouble?

    >
    > Possibly, but this is a simple mock-up, and I was following samples I
    > found online.
    > I was interested in learning a bit about the server-side application
    > of transforms anyway.
    >
    > > In what circumstance will userRows be null?

    >
    > When, for instance, the server has finished sending all users.


    getElementsByTagName is a method of the document object. By
    definition, it always returns a NodeList object. It may not have any
    nodes in the list (i.e. a length of zero) but it is still a NodeList
    object, not null.

    <URL: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-A6C9094 >


    > Right now (again, this is a mock), the server will send
    > 4 user-rows at the time, for a maximum of 4 times.
    > When it reaches the end of the simulkated users, it leaves
    > the response stream clear.
    >
    > > Why not send HTML instead of XML and just append the rows to the table
    > > (insert the HTML as the innerHTML of a div to convert it to a DOM
    > > object, just wrap the trs in table tags)? You could also just grab
    > > the tbody and append it to the current table or replace the current
    > > tbody - done in one go.

    >
    > I actually tried to switch the xsl transformation output from xml to
    > html, just to see
    > if it made any difference, but it didn't.


    >From what you have posted below, your response text is not valid

    HTML. TR elements must be in a table. I don't know how a browser
    treats an XML "tr" node placed into an HTML document.

    > I've been reading around and it seems that, indeed, cloneNode does not
    > copy
    > all attributes and/or event handlers (although in my case the href
    > attribute is cloned),


    Whether or not handlers are cloned depends on how they are added and
    which browser you are using.

    <URL:
    http://groups.google.com.au/group/c...onclick handler&rnum=1&hl=en#71c9b4debcac1543
    >


    cloneNode *should* copy all attributes and their values, whether or
    not it does might be browser dependent:

    <URL: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-3A0ED0A4 >


    [...]
    > The source of users is an xml file as follows: (I'll show you a single
    > user, but there are 4 in the actual file)
    > <?xml version="1.0" encoding="UTF-8"?>
    > <ListPage>
    > <User id="1">
    > <Login>fred</Login>
    > <Password>Wilma</Password>
    > <FirstName>Fred</FirstName>
    > <LastName>Flinstone</LastName>
    > </User>
    > </ListPage>
    >
    > The xslt, with the first 2 columns set to be links:
    > <?xml version="1.0" encoding="utf-8"?>
    > <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
    > Transform">
    > <xsl:eek:utput method="xml" encoding="UTF-8" indent="yes" omit-xml-
    > declaration="no" standalone="yes" />
    > <xsl:strip-space elements="*" />
    > <xsl:template match="/">
    > <ListChunk>
    > <xsl:for-each select="ListPage/User">
    > <tr>


    There you are, invalid HTML (though it might be fine as XML).

    [...]
    > Using firebug, I've been checking what gets sent by the server to the
    > client, and it seems to be:
    > <ListChunk>
    > <tr>
    > <td><a href="http://www.google.com">1</a></td>
    > <td><a href="http://www.google.com">fred</a></td>
    > <td>Wilma</td>
    > <td>Fred</td>
    > <td>Flinstone</td>
    > </tr>
    > </ListChunk>


    But that's not valid HTML.


    > As I said, changing the output method of the transform from xml to
    > html didn't seem to make any difference.


    Put table tags around the tr's.

    [...]
    > > Do not feed XML to IE.

    >
    > ...so what's the recommended cross-browser 'closest-to-standard-
    > compliance' approach to take for something like this ?


    Most send HTML then put it into the document using innerHTML. Look at
    a couple of AJAX libraries:

    <URL: http://www.ajaxtoolbox.com/ >


    --
    Rob
     
    RobG, May 1, 2007
    #4
  5. Olorin

    Olorin Guest

    Hey Rob,
    thanks again for the help.

    I modified my solution so that the server sends simple xml to the
    browser, and the js function handling the response iterates over it
    and creates the table rows and their content.

    In the meanwhile, I'm still hopeful to find a solution that lets the
    server sends the pre-formatted rows to the client.
    As you suggested, I made the server produce html instead of xml.
    It seems that, in this case, the response is received in the
    responseText (rather than responseXml) of the XmlHttp object in the
    browser's js.

    At this point, if I was handling html content that I could happily
    dump in a div or other container via .innerHtml, I guess I'd be done
    (but I'd still feel uneasy about innerHtml.. I'm that kind of person).
    However, as you;ve seen in the previous example, I was dealing with
    table rows and such...
    ...is there a quick way for me to read the responseText into some tree-
    like structure so that I can then iterate over it as needed (other
    than parsing the html myself) ?

    Thanks again,
    ~O
     
    Olorin, May 3, 2007
    #5
    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. Chameleon

    appendChild & cloneNode

    Chameleon, Jun 1, 2009, in forum: XML
    Replies:
    25
    Views:
    3,836
    Thomas 'PointedEars' Lahn
    Jun 3, 2009
  2. itsme

    XmlDocument and cloneNode

    itsme, Oct 14, 2003, in forum: ASP .Net Building Controls
    Replies:
    0
    Views:
    156
    itsme
    Oct 14, 2003
  3. Csaba  Gabor

    cloneNode and iterating event listeners

    Csaba Gabor, Apr 24, 2006, in forum: Javascript
    Replies:
    2
    Views:
    212
    Csaba Gabor
    Apr 25, 2006
  4. Janis Papanagnou
    Replies:
    1
    Views:
    131
  5. Chameleon

    appendChild & cloneNode

    Chameleon, Jun 1, 2009, in forum: Javascript
    Replies:
    26
    Views:
    285
    Thomas 'PointedEars' Lahn
    Jun 3, 2009
Loading...

Share This Page