PrimeFaces对话框的表单作为输入呈现,ajax破坏/重新创建Bean

时间:2019-05-16 22:28:33

标签: jsf primefaces

我遇到h:form的问题,其中包含composite,而后者又包含p:dialog appendTo="@(body)h:form。选择p:selectOneRadio时,将触发一个ajax,该ajax会以某种方式破坏支持bean (调用了@PostConstruct方法)。

有人有类似的问题here(未提供解决方案)。

Bean

@ManagedBean
@javax.faces.bean.ViewScoped
public class TestBean implements Serializable {
    private String radioValue;

    @PostConstruct
    private void onPostConstruct() { /* ... */ }
    public void init() { /* ... */ }
    public void onCommandButtonAction() { /* ... */ }
    public void onRadioChange() { /* ... */ }

    public String getRadioValue() { return radioValue; }
    public void setRadioValue(String radioValue) { this.radioValue = radioValue; }
}

查看

<!DOCTYPE html>
<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:custom="http://java.sun.com/jsf/composite/components">

    <h:head>
    </h:head>

    <h:body>
        <f:event type="preRenderComponent" listener="#{testBean.init}"/>

        <h:form id="form">
            <custom:radioComponent id="radioComponent"/>
        </h:form>
    </h:body>
</html>

复合(radioComponent)

<ui:composition 
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:p="http://primefaces.org/ui"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:composite="http://java.sun.com/jsf/composite"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:dialog="http://java.sun.com/jsf/composite/components/dialogs">

    <composite:interface>
    </composite:interface>

    <composite:implementation>
        <p:selectOneRadio
                id="selectOneRadio"
                value="#{testBean.radioValue}">

            <f:selectItem itemLabel="a" itemValue="a" />
            <f:selectItem itemLabel="b" itemValue="b" />

            <p:ajax event="change"
                    listener="#{testBean.onRadioChange}"
                    update="text"/>
        </p:selectOneRadio>

        <h:outputText id="text" value="#{testBean.radioValue}"/>

        <!-- if not present, @PostConstruct is NOT invoked -->
        <dialog:formDlg id="formDlg"/>
    </composite:implementation>
</ui:composition>

对话框

<ui:composition 
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:p="http://primefaces.org/ui"
        xmlns:composite="http://java.sun.com/jsf/composite">

    <composite:interface>
    </composite:interface>

    <composite:implementation>
        <!--
        if appendTo="@(body)" is ommited,
        radio button does not destroy bean
        i.e. @PostConstruct is NOT invoked
        -->
        <p:dialog
                id="formDlg"
                widgetVar="formDlgWidget"
                modal="true" 
                appendTo="@(body)">

            <h:form id="dialogForm">
                <!--
                does not work if appendTo="@(body)" is present
                if appendTo="@(body)" is ommited,
                action is getting invoked...
                -->
                <p:commandButton
                        value="click"
                        action="#{testBean.onCommandButtonAction}"/>
            </h:form>
        </p:dialog>
    </composite:implementation>
</ui:composition>

请注意,对话框的表单将作为输入呈现(我期待表单标签):

form rendered as input

编辑

正如Kukeltje指出的那样,这是不良设计的结果。表单嵌套,即使嵌套表单被appendTo="@(body)"移出,它也是最初非法的构造,正如BalusC所说的here。因此,教训是复合材料绝不能用外部形式包装,因为它们可能包含自己的形式

WORKAROUND

如果要避免重写整个页面的组成,可以使用OmniFaces实用工具标签o:moveComponent从父表单中移出。

<o:moveComponent
        id="moveDialog"
        for=":#{facesContext.viewRoot.clientId}" 
        destination="ADD_LAST">
    <dialog:formDlg id="formDlg"/>
</o:moveComponent>

注意,for="{cc.attrs.parentFormClientId}"解析为空字符串,即使提供了此属性也是如此。

0 个答案:

没有答案