Search code examples
jsfjsf-2rendered-attribute

Primefaces: conditionally rendered component doesn't get submitted


I have a field that is rendered conditionally, based on a dropdown. All of that goes without problem, but when I submit the form of which the newly rendered component should be part of, it doesn't get submitted.

The code is fairly straightforward:

<h:form id="form">
    <p:layout id="layout">
        ...
        <p:layoutUnit id="layoutUnit">
            ...
            <p:panel id="panel">
                <p:outputPanel id="container1">
                    <p:selectOneMenu id="value1" value="#{bean.value1}">
                        <f:selectItem itemValue="1"/>
                        <f:selectItem itemValue="2"/>
                        <f:selectItem itemValue="3"/>
                        <f:selectItem itemValue="18"/>
                        <p:ajax event="change" update="container2"/>
                    </p:selectOneMenu> 
                </p:outputPanel>

                <p:outputPanel id="container2">
                    <p:inputText id="value2" 
                                 value="#{bean.value2}" 
                                 rendered="#{bean.value1 eq 18}"
                                 >
                    </p:inputText>
                </p:outputPanel>
            </panel>

            <div id="buttons">
                <p:commandButton id="commandButton" action="#{bean.save}" value="save" />
            </div>
        </layoutUnit>
    </layout>
</form>

Tried possible solutions:

I can think of a few scenarios causing this behaviour:

  1. 'Rendered' seems to re-evaluate based on values in the backing bean, rather than the new values given in the UI (if it defaults to 1, it is 1 again on submit, not 18). The component therefore doesn't get submitted.
  2. The added component isn't correctly added to the form, and therefore not submitted.
  3. ?

Option 1 seems to be the most likely one, but could anyone point me in the right direction?

I work with WAS8.5 (so JSF2.0), Primefaces and CDI.


Solution

  • Using CDI's @ConversationScoped in addition to @Named is a solution. That scope works comparable to the @ViewScoped from JSF.

    To get it working I've simply added code from the example here. So in short:

    Bean.java

    @Named
    @ConversationScoped
    public class Bean implements Serializable{
    
        @Inject
        private Conversation conversation;
    
        Bean values, getters & setters
    
        public void initConversation(){
            if (!FacesContext.getCurrentInstance().isPostback() && conversation.isTransient()) {         
                conversation.begin();
            }
        }
    
        public String endConversation(){
            if(!conversation.isTransient()){
                conversation.end();
            }
        }
    
        public String navigateAwayFromScreen(){
            endConversation();
        }
    }
    

    beanOutput.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:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:p="http://primefaces.org/ui"
        xmlns:ui="http://java.sun.com/jsf/facelets">
    
        <f:event listener="#{bean.initConversation}" type="preRenderView"/>
    
        <h:form id="form">
            <p:layout id="layout">
                ...
                <p:layoutUnit id="layoutUnit">
                    ...
                    <p:panel id="panel">
                        <p:outputPanel id="container1">
                            <p:selectOneMenu id="value1" value="#{bean.value1}">
                                <f:selectItem itemValue="1"/>
                                <f:selectItem itemValue="2"/>
                                <f:selectItem itemValue="3"/>
                                <f:selectItem itemValue="18"/>
                                <p:ajax event="change" update="container2"/>
                            </p:selectOneMenu> 
                        </p:outputPanel>
    
                        <p:outputPanel id="container2">
                            <p:inputText id="value2" 
                                         value="#{bean.value2}" 
                                         rendered="#{bean.value1 eq 18}"
                                         >
                            </p:inputText>
                        </p:outputPanel>
                    </panel>
    
                    <div id="buttons">
                        <p:commandButton id="commandButton" action="#{bean.navigateAwayFromScreen}" value="Go away!" />
                    </div>
                </layoutUnit>
            </layout>
        </form>
    </html>
    

    Now, a conversation gets started when you open the page (due to the initConversation being called from the top of beanOutput.xhtml), and ended when you click the button navigateAwayFromScreen.

    (However, if you are able to work with JSF2.2, it should be possible to use the @ViewScoped in combination with CDI. (I say 'should': I am not in the situation to upgrade. But it may be useful to others to examine)).