12 min read

One of the more advanced features of the Facelets framework is the ability to define complex templates containing dynamic nested content.

What is a template?
The Merriam-Webster dictionary defines the word “template” as “a gauge, pattern, or mold (as a thin plate or board) used as a guide to the form of a piece being made” and as “something that establishes or serves as a pattern.” In the context of user interface design for the Web, a template can be thought of as an abstraction of a set of pages in the web application.
A template does not define content, but rather it defines placeholders for content, and provides the layout, orientation, flow, structure, and logical organization of the elements on the page. We can also think of templates as documents with “blanks” that will be filled in with real data and user interface controls at request time. One of the benefits of templating is the separation of content from presentation, making the maintenance of the views in our web application much easier.

The <ui:insert> tag has a name attribute that is used to specify a dynamic content region that will be inserted by the template client. When Facelets renders a UI composition template, it attempts to substitute any <ui:insert> tags in the Facelets template document with corresponding <ui:define> tags from the Facelets template client document. Conceptually, the Facelets composition template transformation process can be visualized as follows:

JSF 1.2 Components

In this scenario, the browser requests a Facelets template client document in our JSF application. This document contains two <ui:define> tags that specify named content elements and references a Facelets template document using the <ui:composition> tag’s template attribute. The Facelets template document contains two <ui:insert> tags that have the same names as the <ui:define> tags in the client document, and three <ui:include> tags for the header, footer, and navigation menu.

This is a good example of the excellent support that Facelets provides for the Composite View design pattern. Facelets transforms the template client document by merging any content it defines using <ui:define> tags with the content insertion points specified in the Facelets template document using the <ui:insert> tag. The result of merging the Facelets template client document with the Facelets template document is rendered in the browser as a composite view.

While this concept may seem a bit complicated at first, it is actually a powerful feature of the Facelets view defi nition framework that can greatly simplify user interface templating in a web application. In fact, the Facelets composition template document can itself be a template client by referencing another composition template. In this way, a complex hierarchy of templates can be used to construct a flexible, multi-layered presentation tier for a JSF application.

Without the Facelets templating system, we would have to copy and paste view elements such as headers, footers, and menus from one page to the next to achieve a consistent look and feel across our web application. Facelets templating enables us to define our look and feel in one document and to reuse it across multiple pages. Therefore, if we decide to change the look and feel, we only have to update one document and the change is immediately propagated to all the views of the JSF application.

Let’s look at some examples of how to use the Facelets templating feature.

A simple Facelets template

The following is an example of a simple Facelets template. It simply renders a message within an HTML <h2> element. Facelets will replace the “unnamed” <ui:insert> tag (without the name attribute) in the template document with the content of the <ui:composition> tag from the template client document.

template01.jsf
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html


>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Facelets template example</title>
<link rel="stylesheet" type="text/css" href="/css/style.css" />
</head>
<body>
<h2><ui:insert /></h2>
</body>
</html>

A simple Facelets template client

Let’s look at a simple example of Facelets templating. The following page is a Facelets template client document. (Remember: you can identify a Facelets template client by looking for the existence of the template attribute on the <ui:composition> tag.) The <ui:composition> tag simply contains the text Hello World.

templateClient01.jsf
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ui:composition example</title>
</head>
<body>
<ui:composition template="/WEB-INF/templates/template01.jsf">
Hello World
</ui:composition>
<ui:debug />
</body>
</html>

The following screenshot displays the result of the Facelets UI composition template transformation when the browser requests templateClient01.jsf.

JSF 1.2 Components

Another simple Facelets template client

The following Facelets template client example demonstrates how a template can be reused across multiple pages in the JSF application:

templateClient01a.jsf
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ui:composition example</title>
</head>
<body>
<ui:composition template="/WEB-INF/templates/template01.jsf">
How are you today?
</ui:composition>
<ui:debug />
</body>
</html>

The following screenshot displays the result of the Facelets UI composition template transformation when the browser requests templateClient01a.jsf:

JSF 1.2 Components

A more complex Facelets template

The Facelets template in the previous example is quite simple and does not demonstrate some of the more advanced capabilities of Facelets templating. In particular, the template in the previous example only has a single <ui:insert> tag, with no name attribute specified. The behavior of the unnamed <ui:insert> tag is to include any content in the referencing template client page.

In more complex templates, multiple <ui:insert> tags can be used to enable template client documents to defi ne several custom content elements that will be inserted throughout the template. The following Facelets template document declares three named <ui:insert> elements. Notice carefully where these tags are located.

template02.jsf
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html


>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><ui:insert name="title" /></title>
<link rel="stylesheet" type="text/css" href="/css/style.css" />
</head>
<body>
<ui:include src="/WEB-INF/includes/header.jsf" />
<h2><ui:insert name="header" /></h2>
<ui:insert name="content" />
<ui:include src="/WEB-INF/includes/footer.jsf" />
</body>
</html>

In the following example, the template client document defines three content elements named title, header, and content using the <ui:define> tag. Their position in the client document is not important because the template document determines where this content will be positioned.

templateClient02.jsf
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ui:composition example</title>
</head>
<body>
<ui:composition template="/WEB-INF/templates/template02.jsf">
<ui:define name="title">Facelet template example</ui:define>
<ui:define name="header">Hello World</ui:define>
<ui:define name="content">Page content goes here.</ui:define>
</ui:composition>
<ui:debug />
</body>
</html>

The following screenshot displays the result of a more complex Facelets UI composition template transformation when the browser requests the page named templateClient02.jsf.

JSF 1.2 Components

The next example demonstrates reusing a more advanced Facelets UI composition template. At this stage, we should have a good understanding of the basic concepts of Facelets templating and reuse.

templateClient02a.jsf
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ui:composition example</title>
</head>
<body>
Facelets Components
[ 78 ]
<ui:composition template="/WEB-INF/templates/template02.jsf">
<ui:define name="title">Facelet template example</ui:define>
<ui:define name="header">Thanks for visiting!</ui:define>
<ui:define name="content">We hope you enjoyed our site.</ui:define>
</ui:composition>
<ui:debug />
</body>
</html>

The next screenshot displays the result of the Facelets UI composition transformation when the browser requests templateClient02a.jsf. We can follow this pattern to make a number of JSF pages reuse the template in this manner to achieve a consistent look and feel across our web application.

JSF 1.2 Components

Decorating the user interface

The Facelets framework supports the definition of smaller, reusable view elements that can be combined at runtime using the Facelets UI tag library. Some of these tags, such as the <ui:composition> and <ui:component> tags, trim their surrounding content. This behavior is desirable when including content from one complete XHTML document within another complete XHTML document.

There are cases, however, when we do not want Facelets to trim the content outside the Facelets tag, such as when we are decorating content on one page with additional JSF or HTML markup defi ned in another page.

For example, suppose there is a section of content in our XHTML document that we want to wrap or “decorate” with an HTML <div> element defined in another Facelets page. In this scenario, we want all the content on the page to be displayed, and we are simply surrounding part of the content with additional markup defined in another Facelets template. Facelets provides the <ui:decoration> tag for this purpose.

Decorating content on a Facelets page

The following example demonstrates how to decorate content on a Facelets page with markup from another Facelets page using the <ui:decoration> tag. The <ui:decoration> tag has a template attribute and behaves like the <ui:composition> tag. Facelets templating typically uses the <ui:composition>. It references a Facelets template document that contains markup to be included in the current document. The main difference between the <ui:composition> tag and the <ui:decoration> tag is that Facelets trims the content outside the <ui:composition> tag but does not trim the content outside the <ui:decoration> tag.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ui:decorate example</title>
<link rel="stylesheet" type="text/css" href="css/style.css" />
</head>
<body>
Text before will stay.
<ui:decorate template="/WEB-INF/templates/box.jsf">
<span class="header">Information Box</span>
<p>This is the first line of information.</p>
<p>This is the second line of information.</p>
<p>This is the third line of information.</p>
</ui:decorate>
Text after will stay.
<ui:debug />
</body>
</html>

Creating a Facelets decoration

Let’s examine the Facelets decoration template referenced by the previous example. The following source code demonstrates how to create a Facelets template to provide the decoration that will surround the content on another page.

As we are using a <ui:composition> tag, only the content inside this tag will be used. In this example, we declare an HTML <div> element with the “box” CSS style class that contains a single Facelets <ui:insert> tag. When Facelets renders the above Facelets page, it encounters the <ui:decorate> tag that references the box.jsf page. The <ui:decorate> tag will be merged together with the associated decoration template and then rendered in the view. In this scenario, Facelets will insert the child content of the <ui:decorate> tag into the Facelets decoration template where the <ui:insert> tag is declared.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html



>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Box</title>
</head>
<body>
<ui:composition>
<div class="box">
<ui:insert />
</div>
</ui:composition>
</body>
</html>

The result is that our content is surrounded or “decorated” by the <div> element. Any text before or after the <ui:decoration> is still rendered on the page, as shown in the next screenshot:

JSF 1.2 Components

The included decoration is rendered as is, and is not nested inside a UI component as demonstrated in the following Facelets debug page:

JSF 1.2 Components

LEAVE A REPLY

Please enter your comment!
Please enter your name here