【问题标题】:Dynamically instantiate composite components on page, on clicking CommandButton在页面上动态实例化复合组件,点击命令按钮
【发布时间】:2016-03-29 08:37:09
【问题描述】:

接着传说中的 BalusC 对这篇文章的回复:

How to programmatically or dynamically create a composite component in JSF 2

如果我有足够的积分,我会在该帖子上附加评论 - 但我没有足够的积分。

问题如下。

我正在尝试设置一个命令按钮,它将一个 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);
}

当我点击命令按钮时,记录如下:

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 不为空(已检查)。 所以,很明显,也许 - parent 为空,这就是问题所在。

那么我怎样才能更好地参考UIComponent parent 呢? 我是否需要让它引用 xhtml 文件中的某些内容?我假设它需要某种占位符来充当父级(?)。现在 xhtml 页面上的所有内容都是 commandButton。

谢谢大家。

【问题讨论】:

    标签: jsf jsf-2.2 composite-component


    【解决方案1】:

    parent 应该代表您希望在其中包含复合组件的组件。

    想象一下,您最终希望得到这个简单的 XHTML 表示:

    <h:panelGroup id="questions">
        <your:questionComposite />
    </h:panelGroup>
    

    然后,您应该将 &lt;h:panelGroup&gt; 组件准确地提供为 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) {
        // ...
    }
    

    与具体问题无关:这里存在思维/设计错误。您应该使用&lt;ui:repeat&gt;&lt;your:compositeComponent&gt;,然后从@ViewScoped bean 向&lt;ui:repeat&gt; 提供代表组合模型值的动态大小的实体列表。

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

    另见:

    【讨论】:

    • 谢谢 BalusC -- 非常感谢。我要花一点时间才能深入研究这个问题,但是您的回答一如既往地彻底,真的很有帮助。感谢 Tiny 对风格的评论。祝大家圣诞快乐。
    • 作为脚注,最终这个解决方案似乎适用于上下文 - stackoverflow.com/questions/3409053/… .. 换句话说 - 不需要复合组件。
    • 确实没有复合组件在技术上是唯一解决方案的情况。
    猜你喜欢
    • 2019-09-03
    • 2020-11-16
    • 2017-09-10
    • 2020-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    相关资源
    最近更新 更多