PrimeFaces nested form inside p:dialog with appendTo="@(body)

Michele Mariotti picture Michele Mariotti · Oct 28, 2014 · Viewed 11.4k times · Source

I have this fragment:

<h:form id="form">

    <!-- other content -->

    <p:panel id="panel" header="test">
        <p:inputText id="input1" value="#{viewScope.prop1}" required="true" />
        <p:commandButton id="button1" process="@form" update="@form @widgetVar(dialog)"
            oncomplete="PF('dialog').show()" value="ok" />
    </p:panel>

    <!-- other content -->

</h:form>

<p:dialog id="dialog" header="dialog" widgetVar="dialog" modal="true">
    <h:form id="form2">
        <p:inputText id="input2" value="#{viewScope.prop1}" required="true" />
        <p:commandButton id="button2" process="@form" update="@form" value="ok" />
    </h:form>
</p:dialog>

and all is working as expected.

What I'd like to achieve is this:

<h:form id="form">

    <!-- other content -->

    <!-- fragment start -->
    <!-- this fragment will be on its own file and included via ui:include (or inside composite component) -->
    <p:panel id="panel" header="test">
        <p:inputText id="input1" value="#{viewScope.prop1}" required="true" />
        <p:commandButton id="button1" process="@form" update="@form @widgetVar(dialog)"
            oncomplete="PF('dialog').show()" value="ok" />
    </p:panel>

    <p:dialog id="dialog" header="dialog" widgetVar="dialog" modal="true" appendTo="@(body)">
        <h:form id="form2">
            <p:inputText id="input2" value="#{viewScope.prop1}" required="true" />
            <p:commandButton id="button2" process="@form" update="@form" value="ok" />
        </h:form>
    </p:dialog>
    <!-- fragment end -->

    <!-- other content -->

</h:form>

but I unsuccessfully tried some combination of process and update for button1 resulting in process anything... input1 is even resetting...

So, how to build a p:dialog that can be shipped inside a fragment or a composite comp and that is excluded from outside form?

Note that using:

<h:form id="form">

    <!-- other content -->

    <ui:include src="panel.xhtml" />

    <!-- other content -->

</h:form>

<ui:include src="dialog.xhtml" />

is not an acceptable solution.

I'm on JSF 2.2.8 (mojarra) and PF 5.1

Answer

Michele Mariotti picture Michele Mariotti · Mar 17, 2016

Finally, I found a way using OmniFaces, with <o:moveComponent /> :

page:

<h:form id="form">

    <!-- other content -->

    <ui:include src="/fragment/with/inner/form.xhtml" />

    <!-- other content -->

</h:form>

fragment:

<ui:composition>    
    <p:inputText id="outerText" value="#{viewScope.text}" />

    <p:commandButton id="openButton" process="@form" update="@widgetVar(testDialog)"
        oncomplete="PF('testDialog').show()" value="open" />
    <o:moveComponent id="move" for=":#{facesContext.viewRoot.clientId}" destination="ADD_LAST">
        <h:form id="innerForm">
            <p:dialog id="dialog" widgetVar="testDialog" header="test dialog">
                <p:inputText id="innerText" value="#{viewScope.text}" />

                <f:facet name="footer">
                    <p:commandButton id="confirmButton" process="@form" update=":form"
                        oncomplete="if(!args.validationFailed) PF('testDialog').hide()" 
                        value="submit" />
                </f:facet>
            </p:dialog>
        </h:form>
    </o:moveComponent>
</ui:composition>

This will cause some warning:

WARNING Unable to save dynamic action with clientId 'form:innerForm:dialog' because the UIComponent cannot be found
WARNING Unable to save dynamic action with clientId 'form:innerForm:innerText' because the UIComponent cannot be found
WARNING Unable to save dynamic action with clientId 'form:innerForm:confirmButton' because the UIComponent cannot be found

because the restored components are not re-removed on subsequent RESTORE_VIEW for postback.

These warnings, as for my experiments, are harmless and could be safely ignored.

However I opened a pull request to eventually fix it.