如何编写一个自定义组件,它在呈现一些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"); 
}