I don't have a working environment in front of me, but I believe you don't want to you use <ui:define>
, but instead you want to use <ui:param>
and then use ${x}
or #{x}
(or forget which or if it matters) to pull them out.
So, for you example you would have:
<ui:param name="title" value="PageUID_123" />
And then:
<meta name="pageid" content="${title}"/>
My only concern with that is that you are using include to have nice templates, i.e.
template:
<html>
<head>
<meta name="pageid" content="${title}"/>
</head>
<body>
<ui:insert name="content" />
</body>
</html>
Inner page:
<html xmlns="...so many">
<ui:param name="title" value="PageUID_123" />
<ui:define name="content">
<!-- content goes here -->
</ui:define>
</html>
And I really don't know if that will fly...
Edit: You may want to try ${title}
or #{title}
just for kicks the way you're doing it now, it might Just Work.
Indeed, you cannot use the "good old" JSTL in Facelets anymore the way as you would do in JSP. Facelets only supports a limited subset of JSTL (and has it already builtin, the JSTL JAR file is in fact superfluous).
You're forced to write a custom tag or better, a custom EL function, for this purpose.
Let's assume that we want to be able to do this:
<ice:graphicImage ... title="#{fmt:formatDate(bean.date, 'yyyy-MM-dd')}" />
Roughly said thus the same what the JSTL <fmt:formatDate>
tag can do, but then in flavor of an EL function so that you can use it everywhere without the need for an "intermediating" tag. We want it to take 2 arguments, a Date
and a SimpleDateFormat
pattern. We want it to return the formatted date based on the given pattern.
First create a final
class with a public static
method which does exactly that:
package com.example.el;
import java.text.SimpleDateFormat;
import java.util.Date;
public final class Formatter {
private Formatter() {
// Hide constructor.
}
public static String formatDate(Date date, String pattern) {
return new SimpleDateFormat(pattern).format(date);
}
}
Then define it as a facelet-taglib
in /META-INF/formatter.taglib.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://example.com/el/formatter</namespace>
<function>
<function-name>formatDate</function-name>
<function-class>com.example.el.Formatter</function-class>
<function-signature>String formatDate(java.util.Date, java.lang.String)</function-signature>
</function>
</facelet-taglib>
Then familarize Facelets with the new taglib in the existing /WEB-INF/web.xml
:
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/META-INF/formatter.taglib.xml</param-value>
</context-param>
(note: if you already have the facelets.LIBRARIES
definied, then you can just add the new path commaseparated)
Then define it in the Facelets XHTML file as new XML namespace:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:fmt="http://example.com/el/formatter"
...
>
Finally you can use it as intended:
<ice:graphicImage ... title="#{fmt:formatDate(bean.date, 'yyyy-MM-dd')}" />
Hope this helps.
Best Answer
Introduction
JSTL
<c:xxx>
tags are all taghandlers and they are executed during view build time, while JSF<h:xxx>
tags are all UI components and they are executed during view render time.Note that from JSF's own
<f:xxx>
and<ui:xxx>
tags only those which do not extend fromUIComponent
are also taghandlers, e.g.<f:validator>
,<ui:include>
,<ui:define>
, etc. The ones which extend fromUIComponent
are also JSF UI components, e.g.<f:param>
,<ui:fragment>
,<ui:repeat>
, etc. From JSF UI components only theid
andbinding
attributes are also evaluated during view build time. Thus the below answer as to JSTL lifecycle also applies to theid
andbinding
attributes of JSF components.The view build time is that moment when the XHTML/JSP file is to be parsed and converted to a JSF component tree which is then stored as
UIViewRoot
of theFacesContext
. The view render time is that moment when the JSF component tree is about to generate HTML, starting withUIViewRoot#encodeAll()
. So: JSF UI components and JSTL tags doesn't run in sync as you'd expect from the coding. You can visualize it as follows: JSTL runs from top to bottom first, producing the JSF component tree, then it's JSF's turn to run from top to bottom again, producing the HTML output.<c:forEach>
vs<ui:repeat>
For example, this Facelets markup iterating over 3 items using
<c:forEach>
:...creates during view build time three separate
<h:outputText>
components in the JSF component tree, roughly represented like this:...which in turn individually generate their HTML output during view render time:
Note that you need to manually ensure the uniqueness of the component IDs and that those are also evaluated during view build time.
While this Facelets markup iterating over 3 items using
<ui:repeat>
, which is a JSF UI component:...already ends up as-is in the JSF component tree whereby the very same
<h:outputText>
component is during view render time being reused to generate HTML output based on current iteration round:Note that the
<ui:repeat>
as being aNamingContainer
component already ensured the uniqueness of the client ID based on iteration index; it's also not possible to use EL inid
attribute of child components this way as it is also evaluated during view build time while#{item}
is only available during view render time. Same is true for anh:dataTable
and similar components.<c:if>
/<c:choose>
vsrendered
As another example, this Facelets markup conditionally adding different tags using
<c:if>
(you can also use<c:choose><c:when><c:otherwise>
for this):...will in case of
type = TEXT
only add the<h:inputText>
component to the JSF component tree:While this Facelets markup:
...will end up exactly as above in the JSF component tree regardless of the condition. This may thus end up in a "bloated" component tree when you have many of them and they are actually based on a "static" model (i.e. the
field
does not ever change during at least the view scope). Also, you may run into EL trouble when you deal with subclasses with additional properties in Mojarra versions before 2.2.7.<c:set>
vs<ui:param>
They are not interchangeable. The
<c:set>
sets a variable in the EL scope, which is accessible only after the tag location during view build time, but anywhere in the view during view render time. The<ui:param>
passes an EL variable to a Facelet template included via<ui:include>
,<ui:decorate template>
, or<ui:composition template>
. Older JSF versions had bugs whereby the<ui:param>
variable is also available outside the Facelet template in question, this should never be relied upon.The
<c:set>
without ascope
attribute will behave like an alias. It does not cache the result of the EL expression in any scope. It can thus perfectly fine be used inside for example iterating JSF components. Thus, e.g. below will work fine:It's only not suitable for e.g. calculating the sum in a loop. For that instead use EL 3.0 stream:
Only, when you set the
scope
attribute with one of allowable valuesrequest
,view
,session
, orapplication
, then it will be evaluated immediately during view build time and stored in the specified scope.This will be evaluated only once and available as
#{dev}
throughout the entire application.Use JSTL to control JSF component tree building
Using JSTL may only lead to unexpected results when being used inside JSF iterating components such as
<h:dataTable>
,<ui:repeat>
, etc, or when JSTL tag attributes depend on results of JSF events such aspreRenderView
or submitted form values in the model which aren't available during view build time. So, use JSTL tags only to control flow of JSF component tree building. Use JSF UI components to control flow of HTML output generation. Do not bind thevar
of iterating JSF components to JSTL tag attributes. Do not rely on JSF events in JSTL tag attributes.Anytime you think you need to bind a component to the backing bean via
binding
, or grab one viafindComponent()
, and create/manipulate its children using Java code in a backing bean withnew SomeComponent()
and what not, then you should immediately stop and consider using JSTL instead. As JSTL is also XML based, the code needed to dynamically create JSF components will become so much better readable and maintainable.Important to know is that Mojarra versions older than 2.1.18 had a bug in partial state saving when referencing a view scoped bean in a JSTL tag attribute. The whole view scoped bean would be newly recreated instead of retrieved from the view tree (simply because the complete view tree isn't available yet at the point JSTL runs). If you're expecting or storing some state in the view scoped bean by a JSTL tag attribute, then it won't return the value you expect, or it will be "lost" in the real view scoped bean which is restored after the view tree is built. In case you can't upgrade to Mojarra 2.1.18 or newer, the work around is to turn off partial state saving in
web.xml
like below:See also:
@ViewScoped
fails in tag handlersTo see some real world examples where JSTL tags are helpful (i.e. when really properly used during building the view), see the following questions/answers:
In a nutshell
As to your concrete functional requirement, if you want to render JSF components conditionally, use the
rendered
attribute on the JSF HTML component instead, particularly if#{lpc}
represents the currently iterated item of a JSF iterating component such as<h:dataTable>
or<ui:repeat>
.Or, if you want to build (create/add) JSF components conditionally, then keep using JSTL. It's way much better than verbosely doing
new SomeComponent()
in java.See also: