【问题标题】:Programmatically create and add composite component in backing bean以编程方式在支持 bean 中创建和添加复合组件
【发布时间】:2013-03-27 13:12:42
【问题描述】:

我正在使用动态仪表板,用户可以在其中随意固定和删除项目。现在我有一个问题,我想从支持 bean 将现有的复合组件添加到视图中。我试图从互联网上找到正确的方法来做到这一点,但到目前为止还没有成功。这是我要添加的简单复合组件:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.org/ui"
      xmlns:composite="http://java.sun.com/jsf/composite">
    <!-- INTERFACE -->
    <cc:interface>

    </cc:interface>

    <!-- IMPLEMENTATION -->
    <cc:implementation>
        <h:outputText value="TEST"/>
    </cc:implementation>
</html>

这是应该返回复合组件的代码:

public static UIComponent getCompositeComponent(String xhtml, String namespace) {
    FacesContext fc = FacesContext.getCurrentInstance();
    Application app = fc.getApplication();
    Resource componentResource = app.getResourceHandler().createResource(xhtml, namespace);

    UIPanel facet = (UIPanel) app.createComponent(UIPanel.COMPONENT_TYPE);
    facet.setRendererType("javax.faces.Group");
    UIComponent composite = app.createComponent(fc, componentResource);
    composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, facet);

    return composite;
}

这是我如何使用该功能:

Column column = new Column();
UIComponent test = HtmlUtil.getCompositeComponent("test.xhtml", "comp");
column.getChildren().add(test);

但列内没有呈现任何内容。任何想法如何做到这一点?我不想使用 render="#{bean.isThisRendered}" 方式,因为它不适合我的用例。

【问题讨论】:

  • 出于兴趣(这个话题被糟糕透顶,这会让我前进光年):你在哪里调用 3-liner 调用 HtmlUtil.getCompositeComponent

标签: dynamic jsf-2 facelets composite-component


【解决方案1】:

此代码不完整。之后需要使用FaceletContext#includeFacelet() 将复合组件资源包含在复合组件实现中。这是一个可以完成这项工作的实用方法。拥有父级很重要,因为它是应该在 EL 范围内创建 #{cc} 的上下文。所以这个实用方法也立即将复合添加为给定父级的子级。此外,给复合组件一个固定的 ID 也很重要,否则 JSF 将无法处理复合内的任何表单/输入/命令组件。

public static void includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id) {
    // Prepare.
    FacesContext context = FacesContext.getCurrentInstance();
    Application application = context.getApplication();
    FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);

    // This basically creates <ui:component> based on <composite:interface>.
    Resource resource = application.getResourceHandler().createResource(resourceName, libraryName);
    UIComponent composite = application.createComponent(context, resource);
    composite.setId(id); // Mandatory for the case composite is part of UIForm! Otherwise JSF can't find inputs.

    // This basically creates <composite:implementation>.
    UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE);
    implementation.setRendererType("javax.faces.Group");
    composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation);

    // Now include the composite component file in the given parent.
    parent.getChildren().add(composite);
    parent.pushComponentToEL(context, composite); // This makes #{cc} available.
    try {
        faceletContext.includeFacelet(implementation, resource.getURL());
    } catch (IOException e) {
        throw new FacesException(e);
    } finally {
        parent.popComponentFromEL(context);
    }
}

因此,在您的特定示例中,按如下方式使用它:

includeCompositeComponent(column, "comp", "test.xhtml", "someUniqueId");

【讨论】:

  • 非常有趣!是否可以使用这种方法(可能有点改变)来包含外部组件?我不想使用现有资源,而是希望包含未在应用程序中定义的组件。
  • @fnst:如有必要,您可以使用自定义资源处理程序控制资源处理。只要您最终得到一个有效的URL,它基本上可以指向所有内容(包括file://http:// 等,甚至自定义协议,以便理论上可以访问数据库)。
  • 感谢您的回答,必须尝试一下:)是否也可以将值表达式添加为复合组件的属性?
  • 不客气。我不确定你具体问的是什么。
  • 这是你的赏金 :) 无论如何我已经回答了我自己的问题.. 为复合组件添加值表达式的代码,例如在使用 可以通过新的函数参数 Map valueExpressions 和 ExpressionFactory factory = application.getExpressionFactory() 来实现; ELContext ctx = context.getELContext(); for (Map.Entry entry : valueExpressions.entrySet()) { ValueExpression expr = factory.createValueExpression(ctx, entry.getValue(), String.class);复合.setValueExpression(entry.getKey(), expr); }
猜你喜欢
  • 2014-08-16
  • 2016-03-03
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多