1

I have a basic JSF page called Index.xhtml and a backing bean called TestBean.java. Basically I am trying to append a child to a td element in a table after a JSF's ajax call renders the table.

The codes are the following.

Index.xhtml:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
        <h:outputScript library="javascript" name="surveyquestions.js"/>
    </h:head>
    <h:body>
        <h:outputLink value="reset.xhtml">reset</h:outputLink>

        <h:form id="myForm">
            <h:panelGroup id="myTable">
                <table>
                    <tr>
                        <td id="targetParent">
                            targetParent here.
                        </td>
                        <td>
                            <h:commandButton value="Click to append a child">
                                <f:ajax event="click" execute="@form"  render="myTable" listener="#{testBean.m()}" onevent="myAppendChild"  />
                            </h:commandButton>
                        </td>
                    </tr>
                </table>

            </h:panelGroup>
        </h:form>

    </h:body>
</html>

And the backing bean only has one method called m and it does nothing. I have two javascript functions and they are called in <f:ajax event="click" execute="@form" render="myTable" listener="#{testBean.m()}" onevent="myAppendChild" />:

function myAppendChild(data){
    if(data.status == "success"){
        var targetParent = document.getElementById("targetParent")
        alert(targetParent.nodeName);
        alert(targetParent.firstChild.nodeValue);
        var spanTag = document.createElement("span");
        spanTag.innerHTML="child";
        targetParent.appendChild(spanTag);

    }
}

function yourAppendChild(data){
    var addButton = data.source;
    if(data.status == "success"){
        var targetParent = addButton.parentNode.parentNode.cells[0];
        alert(targetParent.nodeName);
        alert(targetParent.firstChild.nodeValue);
        var spanTag = document.createElement("span");
        spanTag.innerHTML="child";
        targetParent.appendChild(spanTag);
    }
}

When I tried to append a child to the td element whose Id is targetParent, I fount that the first javascript function myAppendChild worked OK. However, the second function yourAppendChild only worked if I removed the render="myTable".

If I keep render="myTable", yourAppendChild runs to the end, calls the appendChild without error but somehow the child is not appended.

It seems to me that both functions got the exactly same element and tried to append a child to that element but the second function does not work with render="myTable".

4
  • You always better add/remove or hide/show stuff using JSF... the way you try to accomplish things will give you much troubles (INMO) Commented Jul 22, 2012 at 9:08
  • Hi Daniel, thanks a lot for your kind reply. I think I will hide/show the child part using jsf in the end to solve this problem. Just curious why the second function doesn't work while the first one is ok xD. Commented Jul 22, 2012 at 9:40
  • well.. dunno i guess cause of nulls or undefined in addButton.parentNode.parentNode.cells[0]; , just place a breakpoint in your browser js debugger and do some debugging... Commented Jul 22, 2012 at 9:56
  • I used alert() to debug and it appears that the addButton.parentNode.parentNode.cells[0];is working ok. But thanks for the comment anyway^_^ Commented Jul 22, 2012 at 10:56

1 Answer 1

1

When JSF/ajax renders a view, the HTML DOM tree is partially updated/replaced with new elements. The addButton element in your JS yourAppendChild() function, which is still part of the old HTML DOM tree before the render, isn't a member of the new HTML DOM tree anymore at the moment your JS function runs. You're basically traversing a dangling reference which doesn't point to anything in the current HTML DOM tree anymore. You basically need to grab the addButton element directly from the document instead of from data.source.

But I recommend to forget that JS approach and go for a sane and pure JSF approach. You may find this kickoff example helpful: Recommended JSF 2.0 CRUD frameworks.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi @BalusC thanks a lot for your answer:-) When I used alert(targetParent.nodeName); and alert(targetParent.firstChild.nodeValue); I got the expected nodeName and nodeValue, is it that these nodeName and nodeValue belong to the addButton element which is part of the old DOM tree? But because the yourAppendChild function is called (for the third time) after the page is rendered and the DOM tree updated, by the time the yourAppendChild is called (for the third time), the old DOM tree should not exist anymore.
So it seems that I am referencing something of a non-existing tree and yet I got the nodeName and nodeValue:-) And thanks again for the example. I will try to use less JS and also try to stay with pure JSF approach xD.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.