【发布时间】:2014-05-27 06:29:06
【问题描述】:
我正在尝试在 JSF 页面中动态显示 HtmlInputText。但是,我得到了
javax.faces.FacesException: Cannot add the same component twice: j_idt10:hitDyn
在对页面的第一次请求期间,输入文本呈现良好。该异常发生在页面回发期间,当我在输入组件中输入一些文本并按 Enter 键时。 在 .xhtml 页面中,我有以下代码:
<h:form>
<h:outputLabel value="Welcome!"></h:outputLabel>
<f:metadata>
<f:event type="preRenderView" listener="#{dynamicBacking.addDynComp}" />
</f:metadata>
<h:panelGroup id="dynOuter"></h:panelGroup>
</h:form>
在支持 bean 中,我有以下代码:
@ManagedBean(name="dynamicBacking")
public class DynamicBacking {
public void addDynComp() {
Application app = FacesContext.getCurrentInstance().getApplication();
HtmlInputText hit = (HtmlInputText)app.createComponent(HtmlInputText.COMPONENT_TYPE);
hit.setId("hitDyn");
UIComponent parent = findComponent("dynOuter");
if( parent != null ) {
parent.getChildren().add(hit);
}
}
public UIComponent findComponent(final String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot root = context.getViewRoot();
final UIComponent[] found = new UIComponent[1];
root.visitTree(new FullVisitContext(context), new VisitCallback() {
@Override
public VisitResult visit(VisitContext context, UIComponent component) {
if(component.getId().equals(id)){
found[0] = component;
return VisitResult.COMPLETE;
}
return VisitResult.ACCEPT;
}
});
return found[0];
}
}
我猜想在回发中恢复动态组件的状态存在一些问题。我在 JSF 页面的生命周期中添加动态组件是否为时已晚?我知道在 ASP.NET 中我可以在 Page.Load 阶段添加一个动态控件。但到目前为止,我无法弄清楚如何在 JSF 中实现相同的目标。请帮忙!
【问题讨论】:
-
我猜监听器方法在回发时被调用,它试图再次添加相同的组件,但它已经存在,你会得到一个例外。
-
在回发时调用监听器方法时,组件已经存在是怎么回事?谁在回发期间创建了组件?
-
组件在初始页面加载时添加到树中。执行回发时,您的侦听器会再次被调用,并尝试添加具有相同 ID 的另一个组件。
-
在提供初始页面后树不会被破坏吗?我认为 JSF 会根据每个请求构建一个新的组件树,包括回发。如果没有,JSF 是否将组件树存储在某个地方,以便在回发时不需要重建树?
-
那么这回答了这个问题,因为它解释了为什么该组件存在于回发中。需要在 addDynComp 方法的开头添加以下内容: if( FacesContext.getCurrentInstance().isPostback() ) { return; }
标签: jsf jsf-2 components java-ee-7 dynamic-controls