单击CommandButton

时间:2015-12-23 00:22:43

标签: jsf jsf-2.2 composite-component

继传奇人物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。

谢谢大家。

1 个答案:

答案 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完成。

另见: