我遇到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>
请注意,对话框的表单将作为输入呈现(我期待表单标签):
编辑
正如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}"
解析为空字符串,即使提供了此属性也是如此。