Conditionally render ui:define

conditional-rendering, facelets, jsf, templating

Solution

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?

Problem

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.

Original source

Related problems