1
votes

I have a problem with submitting composite components.

Most of my composite components contain both the input components and the "submit" button. When I tried to put the button still in the same h:form but not in the same composite component, the submitted value seemed to be "lost" somewhere. And, for instance, my validators got called on original values.

Example :

<composite:interface>
  <composite:attribute name="titreContext" required="true"/>
</composite:interface>
<composite:implementation>

    <p:outputPanel id="selectionTitreDetailsPanel" styleClass="selectionTitreDetails">
    <p:outputPanel id="selectionTitreDetailsPanelInner" rendered="#{not empty cc.attrs.titreContext.selected}">

    <p:panelGrid columns="2" id="panelId">
      <h:outputText id="idLabel" value="Id :"/>
      <h:outputText id="id" value="#{cc.attrs.titreContext.selected.titeluid}"/>
      <p:tooltip for="id" value="Identifiant unique"/>
    </p:panelGrid>

    <p:panelGrid columns="2" id="titelePanel">
        <p:outputLabel for="selectTitele" value="Titre :"/>
        <p:selectOneMenu id="selectTitele" value="#{cc.attrs.titreContext.selected.titele}" effect="fold" styleClass="fullWidth">
            <f:selectItems value="#{constants.getTitelesForTypman(cc.attrs.titreContext.selected.titele.typman)}" var="titele" itemLabel="#{titele.titelelil}" itemValue="#{titele}" styleClass="fullWidth"/>
                <p:column styleClass="fullWidth">#{titele.titelelil}</p:column>
        </p:selectOneMenu>      
    </p:panelGrid>

    [...]
    <p:commandButton id="confirmerModifications" icon="small_edit" type="submit" value="Confirmer les modifications" 
                    action="#{elutersEditionContext.confirmeModifsSelection}" process="mandatsTerritorial" 
                    update="mandatsTerritorial #{cc.attrs.notifUpdates}"/>

</composite:implementation>

works.

But putting the p:commandButton out of the composite :

<h:form>
<mylib:mycomponent /*parameters *//>
<p:commandButton /*parameters*/ />
</h:form>

does not work. When I debug my validators, I can see that the modified values where not even submitted. Neither getLocalValue, getSubmittedValue nor getValue is changed.

Is there a syntax in composite component declaration to use to correct this situation ? By the way : when I was writing my components as composite components rather than custom components, retrieving #{asen} in the backing bean just worked.

Thanks in advance.

I am using :

  • PrimeFaces 3.4.1
  • CODI 1.0.5
  • OpenWebBeans 1.1.6
  • MyFaces 2.1.9
  • Tomcat 7.0.32

(update) This very strange problem was caused by h:form nesting.

Very strange because h:form nesting did not perturbate the processing of the first level of composite components, but caused this strange "input lost" in nested composite.

Nesting looked like this :

<h:form>
...
    <p:tabView ...>
        <p:tab>
        <h:form>
            <my:composite ....>
        </h:form>
    </p:tabView>
</h:form>
1

1 Answers

2
votes

You're using a relative client ID in the process attribute of the <p:commandButton>:

<p:commandButton ... process="mandatsTerritorial" />

A relative client ID is relative to the parent NamingContainer component. It will be searched as direct child of the NamingContainer component. If the child is by itself a NamingContainer, then its children would not be searched.

Composite components are by itself in fact also NamingContainer components. If the button is placed in the composite, then this will be searched as direct child of the <cc:implementation>. In your particular case, only the component with id="mandatsTerritorial" will be processed on form submit, including all of its children (note that this component is nowhere visible in the code posted so far, but I'd imagine that you omitted it for brevity).

If the button is placed in <h:form>, then this will be searched as direct child of the <h:form>. However as this is apparently been placed inside the composite (which is, as said, another NamingContainer component), it wouldn't be found and hence basically nothing would be processed. You'd need to fix the process to point to the right client ID. E.g.

<h:form>
    <mylib:mycomponent id="mycomponent" />
    <p:commandButton ... process="@this mycomponent:mandatsTerritorial" />
</h:form>

This way it will process itself (mandatory to invoke the action!) and the component with id="mandatsTerritorial" inside the <cc:implementation> of the composite with id="mycomponent".

As a completely different alternative, which would work just fine in this particular construct, is to remove the process attribute altogether. It defaults to @form already which will thus process the entire form.


Update as per your question update: nesting forms is invalid in HTML. Using the JSF <h:form> representation doesn't change that; you'd still end up with nested forms in HTML. The browser behaviour is unspecified as to which data would be submitted to the server. Make sure that you don't nest <h:form> in JSF as well.