Conditionally render ui:define
Asked Answered
F

2

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.

Fitzhugh answered 3/12, 2012 at 2:10 Comment(3)
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.Gastroenteritis
I am also calling some custom el functions on the data instances. But still I want to display the template's default content.Fitzhugh
If there is no solution should I file an enhancement issue for jsf?Fitzhugh
G
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:

Gastroenteritis answered 21/12, 2012 at 4:51 Comment(6)
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.Fitzhugh
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 <c:if test="#{not empty param.id}"><ui:define name="name">content</ui:define></c:if> is not working. Nothing is rendered.Fitzhugh
What JSF impl/version? I was using Mojarra 2.1.16. Do you have properly declared JSTL c XML namespace?Gastroenteritis
Oh I now see that you were trying to conditionally build <ui:define>. This indeed won't work. You should conditionally build <ui:insert>, exactly as shown in my answer.Gastroenteritis
Hmm your answer also confused me since you were talking about the <ui:define> but your example was with <ui:insert>. Good to know that this is not possible.Fitzhugh
Whoops, I now see it. Sorry for that, I fixed it.Gastroenteritis
D
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

Demirelief answered 23/3, 2017 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.