13

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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
djmj
  • 5,579
  • 5
  • 54
  • 92
  • EL is normally null-safe, so null values should just evaluate empty, not throw a NPE. That you're still getting a NPE suggests that you're doing business logic in getters. Is this true? You'd have to fix that over there. – BalusC Dec 03 '12 at 02:16
  • I am also calling some custom el functions on the data instances. But still I want to display the template's default content. – djmj Dec 03 '12 at 03:04
  • If there is no solution should I file an enhancement issue for jsf? – djmj Dec 07 '12 at 15:26

2 Answers2

12

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:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Oh man using new request bean for validation seems like a big workaround since I definetly need validation. I like jsf but many things you dont think of from start building an app are not that straight-forward to implement. – djmj Dec 22 '12 at 13:23
  • Accidently awarded the bounty to quick. I tested it using a request scoped bean for validation using `@ManagedProperty` as you suggested but it never gets called. Reducing it to test raw request param `content` is not working. Nothing is rendered. – djmj Dec 22 '12 at 14:39
  • What JSF impl/version? I was using Mojarra 2.1.16. Do you have properly declared JSTL `c` XML namespace? – BalusC Dec 22 '12 at 14:57
  • Oh I now see that you were trying to conditionally build ``. This indeed won't work. You should conditionally build ``, exactly as shown in my answer. – BalusC Dec 22 '12 at 15:08
  • Hmm your answer also confused me since you were talking about the `` but your example was with ``. Good to know that this is not possible. – djmj Dec 22 '12 at 16:07
  • Whoops, I now see it. Sorry for that, I fixed it. – BalusC Dec 22 '12 at 16:09
1

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

Community
  • 1
  • 1
Sumit Gulati
  • 665
  • 4
  • 14