继传奇人物BalusC对此帖的回应之后:
How to programmatically or dynamically create a composite component in JSF 2
如果我有足够的分数,我会在该帖子上附上评论 - 但我没有足够的分数。
问题如下。
我正在尝试设置一个commandButton,它将JSF复合组件动态添加到xhtml文件中。打算多次单击它会在页面上放置组件的多个实例。
所以我在XHTML文件上有一个按钮:
<h:commandButton action="#{assessingController.addQuestion}" value="Add a Question"></h:commandButton>
在AssessingController上调用方法:
public void addQuestion() {
UIComponent parent = null;
includeCompositeComponent(parent, "http://xmlns.jcp.org/jsf/composite/components", "questionComposite", "someId");
}
UIComponent parent = null;
- 因为在传递给includeCompositeComponent
之前必须以某种方式对其进行实例化或引用。但是如下所述 - 将其设为null可能会导致空指针异常,(那么我该怎么做呢?)
includeCompositeComponent
方法符合BalusC在上述帖子中提到的JSF 2.2方法:
public void includeCompositeComponent(UIComponent parent, String taglibURI, String tagName, String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIComponent composite = context.getApplication().getViewHandler()
.getViewDeclarationLanguage(context, context.getViewRoot().getViewId())
.createComponent(context, taglibURI, tagName, null);
composite.setId(id);
parent.getChildren().add(composite);
}
当我点击commandButton时,记录如下:
javax.faces.el.EvaluationException: java.lang.NullPointerException
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
at javax.faces.component.UICommand.broadcast(UICommand.java:315) ...
Caused by: java.lang.NullPointerException
at controllers.AssessingController.includeCompositeComponent(AssessingController.java:123)
AssessingController.java:123就是这一行:
parent.getChildren().add(composite);
Composite不为null(选中)。 所以,显然也许, - 父是空的,这就是问题所在。
那么我怎样才能更好地引用UIComponent
父母开始?
我是否需要在xhtml文件中引用它?我假设它需要某种占位符作为父(?)。现在xhtml页面上的所有内容都是commandButton。
谢谢大家。
答案 0 :(得分:1)
parent
应该代表您要在其中包含复合组件的组件。
想象一下,您最终希望以这种简单的XHTML表示结束:
<h:panelGroup id="questions">
<your:questionComposite />
</h:panelGroup>
然后,您应该将<h:panelGroup>
组件准确提供为parent
。
<h:form>
<h:commandButton ... action="#{bean.addQuestion}" />
</h:form>
<h:panelGroup id="questions" />
public void addQuestion() {
UIComponent parent = context.getViewRoot().findComponent("questions");
// ...
}
或者,通过传递具体组件本身:
<h:form>
<h:commandButton ... action="#{bean.addQuestion(questions)}" />
</h:form>
<h:panelGroup id="questions" binding="#{questions}" />
public void addQuestion(UIComponent parent) {
// ...
}
对具体问题 无关:这里存在思考/设计错误。您应该使用<ui:repeat><your:compositeComponent>
,然后从@ViewScoped
bean提供给<ui:repeat>
动态大小的实体列表,以表示复合的模型值。
<h:form>
<h:commandButton ... action="#{bean.addQuestion}" />
</h:form>
<ui:repeat value="#{bean.questions}" var="question">
<your:questionComposite value="#{question}" />
</ui:repeat>
private List<Question> questions;
public void addQuestion() {
questions.add(new Question());
}
任何时候你需要处理支持bean中的原始UIComponent
实例,请暂停并仔细研究或询问你是否真的以正确的方式做事。也许它只属于支持组件,或者只能用纯XHTML完成。