2

I have a JSF 2 master template as follows:

<!DOCTYPE html>
<html lang="#{localeManager.language}" 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">

    <f:view locale="#{localeManager.locale}">
        <h:head>
            <meta charset="UTF-8" />
            <meta http-equiv="X-UA-Compatible" content="IE=edge" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <title><ui:insert name="title">Default Title.</ui:insert></title>

            <!-- Development Stylesheets -->
            <ui:fragment rendered="#{facesContext.application.projectStage eq 'Development'}">
                <h:outputStylesheet name="css/bootstrap.css" library="bootstrap" />
                <h:outputStylesheet name="css/font-awesome.css" library="fontawesome" />
            </ui:fragment>

            <h:outputStylesheet name="css/main.css" library="core" />
            <ui:insert name="header-stylesheet" />

            <!-- Production Stylesheets -->
            <ui:fragment rendered="#{facesContext.application.projectStage eq 'Production'}">
                <h:outputStylesheet name="css/bootstrap.min.css" library="bootstrap" />
                <h:outputStylesheet name="css/font-awesome.min.css" library="fontawesome" />
            </ui:fragment>

            <ui:insert name="header-script" />
        </h:head>

        <h:body>
            <div id="wrapper">
                <div id="header">
                    <ui:insert name="header">Default content</ui:insert>
                </div>

                <div id="body">
                    <ui:insert name="body">Default body</ui:insert>
                </div>

                <div id="footer">
                    <ui:insert name="footer">Default footer</ui:insert>
                </div>
            </div>

            <!-- Development Scripts -->
            <ui:fragment rendered="#{facesContext.application.projectStage eq 'Development'}">
                <h:outputScript name="jquery-2.1.4.js" library="jquery" />
                <h:outputScript name="js/bootstrap.js" library="bootstrap" />
            </ui:fragment>

            <!-- Production Scripts -->
            <ui:fragment rendered="#{facesContext.application.projectStage eq 'Production'}">
                <h:outputScript name="jquery-2.1.4.min.js" library="jquery" />
                <h:outputScript name="js/bootstrap.min.js" library="bootstrap" />
            </ui:fragment>
            <ui:insert name="body-script" />
        </h:body>
    </f:view>
</html>

When deploying it in Wildfly 9.0.1 Final, I see that all my <ui:fragment> attribute gets rendered. Why is that? I am developing using JSF 2.2 framework.

My Faces Project stage is Development.

Note: Of all the answers in SO concerning this issue, none is the solution to this problem (so I did my homework).

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228

1 Answers1

2

The <h:outputStylesheet> and <h:outputScript> are special components. They will during view build time already add the declared stylesheet or script resource to the view via UIViewRoot#addComponentResource() (see Mojarra source code here).

This is regardless of the rendered condition of the component or its parents. In effects, they are basically relocated to the very end of the <h:head> or the <h:body>, depending on the value of target attribute, causing them to not sit inside <ui:fragment> anymore.

Then, during rendering, only their own rendered attribute is considered (and actually also of <h:head>, but that's pointless).

You have 2 options:

  1. Use a view build time tag to conditionally add them to the view. The project stage condition is application scoped anyway.

    <!-- Development Stylesheets -->
    <c:if test="#{facesContext.application.projectStage eq 'Development'}">
        <h:outputStylesheet ... />
        <h:outputStylesheet ... />
    </c:if>
    
    <!-- Production Stylesheets -->
    <c:if test="#{facesContext.application.projectStage eq 'Production'}">
        <h:outputStylesheet ... />
        <h:outputStylesheet ... />
    </c:if>
    
  2. Check the condition in component resource's own rendered attribute. Use if necessary <c:set> to create a short EL variable.

    <c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
    
    <!-- Development Stylesheets -->
    <h:outputStylesheet ... rendered="#{dev}" />
    <h:outputStylesheet ... rendered="#{dev}" />
    
    <!-- Production Stylesheets -->
    <h:outputStylesheet ... rendered="#{not dev}" />
    <h:outputStylesheet ... rendered="#{not dev}" />
    
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • So, if I use JSTL conditional `if`, shouldn't I use the `$` instead of `#`? – Buhake Sindi Aug 27 '15 at 07:49
  • You can, but that's not uniform and unnecessarily confusing to starters. In Facelets, `${}` behaves exactly the same as `#{}`, but in JSP `${}` is immediately ("statically") evaluated while `#{}` is only evaluated on every call ("deferred"). – BalusC Aug 27 '15 at 07:50
  • Thanks. I got the stuff to work with JSTL conditional `if`. – Buhake Sindi Aug 27 '15 at 08:38
  • Thanks too, i spend hours checking why my `ui:fragment` with rendered attribute around it did not worked. – djmj Apr 10 '16 at 18:04