如何编写一个自定义组件,它在呈现一些JavaScript时使用其父级的ID?
问题描述:
我想编写一个呈现javascript函数的自定义组件。它的行为基本上就像onloadscript的omnifaces一样,它将使用其封闭父对象的客户端ID作为javascript函数的参数。如何编写一个自定义组件,它在呈现一些JavaScript时使用其父级的ID?
例子:
<h:panelGroup id="panel">
<my:component />
</h:panelGroup>
我已经开始写这样的自定义组件,使用omnifaces实施onloadscript作为指导。看起来不错,但是当封闭父代是复合组件时,我的自定义组件的实际父代不是复合组件,而是insertChildren标记的父代。
虽然这是有道理的,但这当然不是我想要的行为。
实施例:
<my:composite id="panel">
<my:component />
</my:composite>
我的父的客户端ID:组分不是“面板”如果复合使用在其实施insertChildren标签。
问题:
- 我怎样才能解决这个问题?
- 我的自定义组件可以是一个标记处理程序,它可以在视图根中创建单个资源组件,而不是将实际的UI组件移动到视图根?
答
我终于找到了解决办法。
我已经实现了一个标记处理程序,它在处理标记时将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");
}