Jörg Henke
Jörg Henke

Reputation: 123

jsf2 form in form with ajax

On complex data input forms it may happen that one needs to edit a form in a form. As this is not possible in JSF2, I wonder what better solution could be found for this problem. Here's an example of what I need:

I want to add HobbyBeans on the form of adding a user's name in OuterBean without submitting OuterBean but submitting new values to fill the list. Here's the code example:

    <!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:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
    </h:head>
    <h:body>
        <h:form>
        <h:panelGrid columns="2">
            <h:outputText value="Name" />
            <h:inputText value="#{outerBean.name}" required="true" />
            <h:outputText value="Hobbies" />
            <h:dataTable id="ht" value="#{outerBean.hobbies}" var="h">
                <h:column>
                    <h:outputText value="#{h.hobby}" />
                    <f:facet name="footer">
                        <h:inputText value="#{outerBean.hobby}" required="true" />
                    </f:facet>
                </h:column>
                <h:column>
                    <h:outputText value="#{h.like}" />
                    <f:facet name="footer">
                        <h:inputText value="#{outerBean.like}" required="true" />
                        <h:commandButton action="#{outerBean.addHobby}" value="+" immediate="true">
                            <f:ajax render="ht" />
                        </h:commandButton>
                    </f:facet>
                </h:column>
            </h:dataTable>
        </h:panelGrid>
        </h:form>
    </h:body>
    </html>

Yes, there is no command button for the outer form, but that's not the question here. The commandButton is for the inner form and therefore set attribute immediate = true. Doing this, all fields are NOT checked to be not empty (required-Tag is ignored). But also is the content of this fields ignored and not set into the ajax request. How do I avoid this and send the field values of h.hobby and h.like within the ajax request to the OuterBean?

Here the beans:

    @ManagedBean
    @SessionScoped
    public class OuterBean
    {
        private List<HobbyBean> hobbies;
        private String name;
        private String hobby;
        private Integer like;

        public OuterBean()
        {
            hobbies = new ArrayList<HobbyBean>();
        }

        public String addHobby()
        {
            hobbies.add(new HobbyBean(hobby, like));
            System.out.println("hobbies: " + hobbies.toString());
            return "";
        }

        public String submit()
        {
            System.out.println("name is " + name);
            return "";
        }
    // + getter & setter
    }

    /* ------------------------------------------------------------------------ */

    public class HobbyBean
    {
        private String hobby;
        private Integer like;

        public HobbyBean(String hobby, Integer like)
        {
            this.hobby = hobby;
            this.like = like;
        }

        public String toString()
        {
            return hobby == null ? "" : hobby.concat(",").concat(like == null ? "" : like.toString());
        }
    // + getter & setter
    }

Now what happens when I add a hobby to the bean is that there is no hobby added because the bean fields hobby and like are not set (the list is empty, log is: "hobbies: []"). How can I make it work?

Upvotes: 0

Views: 648

Answers (1)

Tankhenk
Tankhenk

Reputation: 634

Well your hobbies is empty because you don't tell the f:ajax what to submit. IF you want to do a partial submit (i guess that's what you want) You can try the following:

<h:form>
    <h:panelGrid columns="2">
        <h:outputText value="Name" />
        <h:inputText value="#{outerBean.name}" required="true" />
        <h:outputText value="Hobbies" />
        <h:dataTable id="ht" value="#{outerBean.hobbies}" var="h">
            <h:column>
                <h:outputText value="#{h.hobby}" />
                <f:facet name="footer">
                    <h:inputText id="hobby" value="#{outerBean.hobby}" required="true" />
                </f:facet>
            </h:column>
            <h:column>
                <h:outputText value="#{h.like}" />
                <f:facet name="footer">
                    <h:inputText id="like" value="#{outerBean.like}" required="true" />
                    <h:commandButton action="#{outerBean.addHobby()}" value="+" >
                        <f:ajax execute="hobby like" render="ht" />
                    </h:commandButton>
                </f:facet>
            </h:column>
        </h:dataTable>
    </h:panelGrid>
</h:form>

As you can see in the code you tell f:ajax wich part of the form needs to be submitted when you push the button. If you check your bean now you will see that only the hobby and like are added to the bean. The name part will not be submitted. You say all fields are not checked. This is because you use immediate=true this skips validation. I would suggest not to use it. Look here for more information about immediate= true http://balusc.blogspot.nl/2006/09/debug-jsf-lifecycle.html#WhenShouldIUseTheImmediateAttribute Hopes this help you.

Upvotes: 1

Related Questions