Is it possible to conditionally ui:define in jsf? - jsf

I use jsf 1.2 yet
I want to do something like this:
<c:if test="#{'1' eq '1'}">
<ui:define name="title">
<h:panelGrid columns="2" style="background-color: lightblue;">
My special super title
</h:panelGrid>
</ui:define>
</c:if>
this does not work - e.g. even though '1' eq '1' is always true, the ui:define only works when using it without c:if
Is there another way to achieve this?
The usecase is that I have a parent template.xhtml with something like this
<ui:define name="title">
#{empty pageTitle ? 'MyAppName' : pageTitle}
</ui:define>
And I have two applications, App1 and App2. For App1 I have to keep the title as is, e.g.:
#{empty pageTitle ? 'MyAppName' : pageTitle}
for App2 I have to add something fancy there, e.g. the silly panelGrid.
Is there some other semi-clean way around this?
EDIT i have to mention that both apps are using the same pages and templates

Related

JSF: duplicate component id exception when including the same facelets tag twice

I have a facelets tag like this:
<ui:composition>
<h:outputText value="#{label}"/>
<h:inputText id="input" value="#{value}"/>
<h:message for="input"/>
</ui:composition>
Now if I inlcude this facelets tag twice on the same page, I get an exception complaining about duplicate compoment ids. One solution proposed here https://stackoverflow.com/a/21572756/1785730 was to supply a prefix for the id. However, I find it cumbersome having to come up with an id prefix every time I use this facelets tag. By the way, I don't need the id of the h:inputText outside of the tag.
So I'm thinking of two ways how I can fix this:
Is there a way to link the h:message to the h:inputText without having to specify ids?
If not, I could wrap the tag with a NamingContainer. Which element would be appropriate for that? I can't use h:form here, because that tag already goes into a form.
Your page should be like this
<f:view contracts="default" transient="false">
<ui:composition template="/template.xhtml">
<ui:define name="content">
<h:form>
inputs
</h:form>
</ui:define>
</ui:composition>
</f:view>
inside ui composition you should have ui define and in it form and inputs.

jsf set ui:param or use a value that changes dynamically in ui:repeat

I want to update an ui:param value or use something similar in ui:repeat loops with a condition. The idea is something as follows (is just an aprox, not the final implementation but I guess is understandable):
<ui:param name="marginLeftNode" value="#{myBean.initialMarginValue}" />
<ui:repeat value="#{myBean.viewWrapper.linkMap.entrySet().toArray()}" var="map">
<ui:repeat var="link" value="#{map.value}" varStatus="status">
<li style="margin-left: #{marginLeftNode}%" class="ico-#{link.getStyleCss()}-ayuda">
#{link.getTitle()}
</li>
<!-- Code conditions that doesn't works in any way as I've readed in the links after code -->
<c:if test="#{marginLeftNode gt 4}">
<ui:param name="marginLeftNode" value="#{myBean.viewWrapper.nodeList.get(status.index).depth}" />
</c:if>
<ui:fragment rendered="#{marginLeftNode gt 4}">
<ui:param name="marginLeftNode" value="#{myBean.viewWrapper.nodeList.get(status.index).depth}" />
</ui:fragment>
<!-- End code conditions: these are the two solutions c:if and ui:fragmen I tried -->
</ui:repeat>
</ui:repeat>
I can't use c:if inside ui:repeat because doesn't works (Specify conditional rendering of element inside <ui:repeat>? The <c:if> does not seem to work) and I can't use ui:fragment with ui:param because it doesn't works too (Conditional variable definition in JSF)
So, any idea how to solve that?
First of all, avoid of use JSTL if you can use JSF. Here is an answer that explains how JSTL and JSF are executed in different steps -> https://stackoverflow.com/a/3343681/4253629
To redefine conditionally a ui:param, for example, you can do this:
<ui:param
name="marginLeftNode"
value="#{marginLeftNode gt 4 ? myBean.viewWrapper.nodeList.get(status.index).depth : marginLeftNode }"/>
Probably exists another solution, but this works.
Greetings
Changing the ui:param inside the loop has no real value. The real purpose of a ui:param is to pass runtime variables into a template client or included file. By the time your parameter has been passed in, there's little value in changing it. If all you want is to conditionally alter the value of the variable after it's been passed, you could just use JSTL's c:set to set a page-scoped variable that you could then use
<ui:repeat value="#{myBean.viewWrapper.linkMap.entrySet().toArray()}" var="map">
<ui:repeat var="link" value="#{map.value}" varStatus="status">
<li style="margin-left: #{marginLeftNode}%" class="ico-#{link.getStyleCss()}-ayuda">
#{link.getTitle()}
</li>
<c:if test="#{marginLeftNode gt 4}">
<c:set var="marginLeftNode" value="#{myBean.viewWrapper.nodeList.get(status.index).depth}"/>
</c:if>
</ui:repeat>
You could then access your set variable as #{marginLeftNode} anywhere within that view

Conditionally render ui:define

How do I conditionally render a <ui:define>?
The data in the template depends on a required <f:viewParam>.
But if an invalid view parameter is provided, then the <ui:define> should not be rendered since the default content of the template should be used.
I tried using <c:if> but it is not working.
It's not possible to conditionally render/build an <ui:define>. You can only do for its contents. Anything outside <ui:define> is ignored in templates.
Better is to conditionally build the <ui:insert> instead. The <ui:insert> runs during view build time, so it's not possible to conditionally render it by a property which is set via <f:viewParam>. You can only conditionally build it (the <ui:insert> tag itself) using a conditional view build time tag such as JSTL <c:if> which in turn checks the raw request parameter directly (and thus not the <f:viewParam> property).
In the master template, it would look like this, assuming that just the sole presence of the request parameter is sufficient (if you need to perform validation, you'd need to do it inside the EL expression, or in a managed bean wherein the property is preinitialized via #ManagedProperty("#{param.foo}").
E.g., in the master template:
<c:if test="#{not empty param.foo}">
<ui:insert name="content" />
</c:if>
<c:if test="#{empty param.foo}">
<p>Default content</p>
</c:if>
or, more clear but more verbose
<c:choose>
<c:when test="#{not empty param.foo}">
<ui:insert name="content" />
</c:when>
<c:otherwise>
<p>Default content</p>
</c:otherwise>
</c:choose>
See also:
JSTL in JSF2 Facelets... makes sense?
Use <ui:fragment> instead.
<ui:define name="description">
<ui:fragment rendered="false">
<meta name="description" content="do not render" />
</ui:fragment>
</ui:define>
Duplicate of ui:define with rendered="false" attribute still rendering

Template-based facelet tag library

I want to create a facelet component which is backed by template.
Something like that:
<h:panelGroup rendered="#{myBean.isStepActive('step0')}">
<composition template="wizard-step.jspx">
<ui:define name="title">Step One</ui:define>
<ui:define name="text"><p>This describes the step</p></ui:define>
</composition>
</h:panelGroup>
<h:panelGroup rendered="#{myBean.isStepActive('step1')}">
<composition template="wizard-step">
<ui:define name="title">Step Two</ui:define>
(...)
Is seems not to work as the content of wizard-step.jspx is put on any page no matter what renders returns (it seems like the ui: tags are evaluated before all other tags.
Is there a way to accomplish what I want?
A normal custom tag is not powerful enough in my case because it only supports xml attributes but no child elements.
Ok, I found the solution and it's pretty easy.
Just use a normal taglib and use < ui:insert> and < ui:define> like that:
<my:wizardStep>
<ui:insert name="title"><h2>The header comes here</h2>/ui:insert>
</<my:wizardStep>
And in the tag definition:
<ui:composition>
<ui:insert name="title" />
(...)

Conditionally including a template file in ui:composition tag

I am using facelets for templating in my jsf application. I would like to including a template file conditionally in ui:composition tag. If user is logged in the template must be "authorized.xhtml" and if the user is not logged in then the template must be "unauthorized.xhtml". Is there a way to do it? Thanks.
<ui:composition template="/templates/unauthorized.xhtml">
<ui:composition template="/templates/authorized.xhtml">
I am using JSF 1.2.
I would try ternary operation on isAuthorized() attribute, if you have one in your log-in bean:
<ui:composition template="#{loginbean.authorized ? '/templates/authorized.xhtml' : '/templates/unauthorized.xhtml'}">
Or use two <h:panelGroup> tags with appropriate rendered values:
<h:panelGroup rendered="#{loginbean.authorized}">
<ui:decorate template="/templates/authorized.xhtml">
</h:panelGroup>
<h:panelGroup rendered="#{not loginbean.authorized}">
<ui:decorate template="/templates/unauthorized.xhtml">
</h:panelGroup>

Resources