Ответ 1
Это невозможно с помощью стандартного API. Xtreme Biker опубликовал блестящий трюк, в котором значение <ui:param>
указано в <ui:insert>
, которое было бы переопределено (и, следовательно, отсутствует), когда <ui:define>
фактически указано как ответ на Проверить, была ли указана ui: insert в клиенте шаблона
Альтернативой A (hacky) было бы создание специального обработчика меток для задания. <ui:define>
находятся по имени, собранному в поле Map handlers
класса тега CompositionHandler
позади <ui:composition>
. Это (к сожалению) конкретная реализация, Mojarra и MyFaces имеют свои собственные реализации, в соответствии с которыми Моджарра назвал поле handlers
и MyFaces _handlers
.
Поскольку поле просто protected
, самым чистым было бы просто расширить класс тегов-меток CompositionHandler
и выставить по крайней мере ключ в методе apply()
как атрибут FaceletContext
. Однако, поскольку сам класс CompositionHandler
объявлен final
, мы не можем его подклассы. Поэтому мы не можем обойти его как делегата и использовать хакерство для отражения в любом случае.
Вот пример kickoff, основанный на 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
:
<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>
Опять же, это хакерский (как его реализация), я бы не рекомендовал его использовать.