如何在渲染一些javascript时编写使用其父ID的自定义组件?

时间:2017-02-23 15:40:00

标签: javascript jsf-2 jsf-2.2 omnifaces

我想编写一个呈现javascript函数的自定义组件。它基本上表现为omnifaces onloadscript,它将使用其封闭父节点的客户端ID作为javascript函数的参数。

示例:

<h:panelGroup id="panel">
    <my:component />
</h:panelGroup>

我已经开始编写这样的自定义组件,使用omnifaces onloadscript的实现作为指导。到目前为止看起来很好,但是当封闭父组件是复合组件时,我的自定义组件的实际父组件不是复合组件,而是insertChildren标签的父组件。

虽然这是有道理的,但这当然不是我想要的行为。

示例:

<my:composite id="panel">
    <my:component />
</my:composite>

如果组合在其实现中使用了insertChildren标记,则my:component的父级的客户端ID不是“panel”。

问题:

  • 如何解决此问题?
  • 我的自定义组件可以是一个标签处理程序,它可以在视图根目录中创建单个资源组件,而不是移动到视图根目录的实际UI组件吗?

1 个答案:

答案 0 :(得分:0)

我终于找到了解决方案。

我已经实现了一个标记处理程序,它在处理标记时将一个UI组件添加到视图树中。请参阅以下代码中的注释。标签处理程序:

private final TagAttribute someAttribute;

@Override
public void apply(FaceletContext ctx, UIComponent parent) {
    UIComponent parentOfParent = parent != null ? parent.getParent() : null;

    // process only when created
    if (parent != null && parentOfParent == null) {
        Supplier<String> scriptProvider = getScriptProvider(ctx, parent);
        ScriptComponent scriptComponent = new ScriptComponent(scriptProvider);
        parent.getChildren().add(scriptComponent);
        // note: the actual script is obtained when the ScriptComponent is rendered
    }
}

protected Supplier<String> getScriptProvider(FaceletContext ctx, UIComponent target) {
    // this is invoked when the tag is processed, so it's Ok for the EL context
    String someValue = someAttribute.getValue(ctx);

    return () -> {
        // this is invoked by the script component when it is rendered,
        // so we have the correct client ID even if the target is a composite component
        String targetId = target.getClientId();
        return String.format("myFunction('%s', '%s');", targetId, someValue);
    };
}

UI组件:

private final Supplier<String> scriptProvider;

@Override
public void encodeBegin(FacesContext context) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    writer.append("\n");
    writer.startElement("script", this);
    writer.append("\n");

    String script = scriptProvider.get();
    writer.append(script);
    writer.append("\n");
}

@Override
public void encodeEnd(FacesContext context) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    writer.endElement("script");
}