如何以编程方式访问用<ui:define>创建的内容?</ui:define>

时间:2015-04-02 10:22:06

标签: jsf facelets

在上下文中,我可以找到使用<ui:define>构建的内容的信息吗?我想访问在我的bean中使用<ui:define name="title">Some title</ui:define>定义的页面标题。

为了说明我的问题,我可以访问用

定义的变量
<ui:param name="myVariable" value="This is my variable!"/>

通过查看EL上下文中的变量映射器,就像这样

VariableMapper variableMapper = elContext.getVariableMapper();
String myVariable = variableMapper.resolveVariable("myVariable").getValue(elContext).toString();

这适用于<ui:param>,但是如何为<ui:define>完成?

1 个答案:

答案 0 :(得分:2)

这不可能通过标准API实现。 Xtreme Biker发布了一个绝妙的技巧,即&#34;默认&#34; <ui:param>中指定了<ui:insert>值,当Test if ui:insert has been defined in the template client

实际指定为<ui:define>时,该值将被覆盖(因此不存在)

(hacky)替代方案是为作业创建自定义标签处理程序。 <ui:define>的名称是在Map handlers后面的CompositionHandler标记处理程序的<ui:composition>字段中收集的。这是(不幸的是)具体实现,MojarraMyFaces有自己的实现,Mojarra将字段命名为handlers和MyFaces _handlers

由于字段只是protected,最简洁的方法是扩展CompositionHandler代码处理程序类,并至少将apply()方法中的密钥集公开为FaceletContext的属性。但是,由于CompositionHandler类本身已声明为final,因此我们无法对其进行子类化。因此,我们无法将其作为代表包装,并使用一些反射hackery来获取该字段。

这里是一个基于Mojarra的启动示例,它收集了<ui:define>中所有已声明的Map<String, Boolean>处理程序名称,这样您就可以在EL #{defined.foo ? '...' : '...'} #{not defined.foo ? '...' : '...'}中很好地使用它们public class DefineAwareCompositionHandler extends TagHandlerImpl implements TemplateClient { private CompositionHandler delegate; private Map<String, Boolean> defined; @SuppressWarnings("unchecked") public DefineAwareCompositionHandler(TagConfig config) { super(config); delegate = new CompositionHandler(config); try { Field field = delegate.getClass().getDeclaredField("handlers"); field.setAccessible(true); Map<String, DefineHandler> handlers = (Map<String, DefineHandler>) field.get(delegate); if (handlers != null) { defined = new HashMap<>(); for (String name : handlers.keySet()) { defined.put(name, true); } } } catch (Exception e) { throw new FaceletException(e); } } @Override public void apply(FaceletContext ctx, UIComponent parent) throws IOException { ctx.setAttribute("defined", defined); delegate.apply(ctx, parent); } @Override public boolean apply(FaceletContext ctx, UIComponent parent, String name) throws IOException { return delegate.apply(ctx, parent, name); } } my.taglib.xml 1}}。

<tag>
    <tag-name>composition</tag-name>
    <handler-class>com.example.DefineAwareCompositionHandler</handler-class>
</tag>

在自定义<my:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:my="http://example.com/ui" > <ui:insert name="foo"> ... </ui:insert> <div class="#{defined.foo ? 'style1' : 'style2'}"> ... </div> </my:composition> 中注册以下内容:

{{1}}

您可以按照以下方式使用它:

{{1}}

同样,这是hacky(因为它的具体实现),我不建议使用它。

另见: