JSF Central - Inside Facelets - Part 3: Templating and Re-Use
JSF Central

 
 Home 
 
 Products 
 
 Articles & Books 
 
 Resources 
Inside Facelets
 
Inside Facelets - Part 3: Templating and Re-Use
by Jacob Hookom
03 Feb 2006 02:15 EST

This is the third part in a series of articles about Facelets, an alternative view technology for building JSF applications. Facelets is a powerful templating system that enables you to define JSF views using HTML-style templates, reduces the amount of code necessary to integrate components into the view, and doesn't require a web container. This article explains how you can use Facelets for templating inside of your JavaServer Faces projects.


For any view technology to succeed, it must have some aspect of templating and re-use that's both easy to use and understand. Facelets technology solves this issue in a way that is ideal for JavaServer Faces while keeping that sense of familiarity to traditional, tag-based user interfaces. This article covers the possible ways to increase re-use and simplify maintenance on your JavaServer Faces project.

When people first start creating web pages, they often find themselves repeating content across multiple files. As a developer, this can be frustrating when your object-oriented tendencies kick in. Wouldn't it be nice to simply maintain that content in one spot?

Getting Started?

The first approach to templating and re-use is creating a template. A web page is often composed of some basic parts: header, body, and footer. With Facelets, you can pull those common elements into a single page, creating a template with editable areas, as shown in the following sample template:

<!-- template.xhtml -->
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
   <title>Sample Template</title>
</head>
<body>
   <h1>#{title}</h1>
   <div><ui:insert name="menu"/></div>
   <p><ui:insert name="body"/></p>

</body>
</html>

The <ui:insert/> tag for menu and body mark areas that change on a per-page basis. You can create other pages that will use this template and provide content for both your menu and body.

<!-- template-client.xhtml -->
   <!-- content above will be trimmed -->
   <ui:composition template="template.xhtml">
     <ui:param name="title" value="Here's my Title"/>
     <ui:define name="menu">Here's My Menu</ui:define>
     <ui:define name="body">Here's My Body</ui:define>
     </ui:composition>
   <!-- content below will be trimmed -->

This example page introduces another tag: <ui:composition/>. This tag provides a couple features. It trims any content around it. This means you can have a normal HTML page and Facelets will only use or render the content within the <ui:composition/> tag. With this tag, you also have the option of providing a template attribute, which will define how and where its content is layed out.

To pair content within this page and the template, the <ui:define/> tags are used with names that match the <ui:insert/> tags from the template above. For simply passing variables or text, you can use the <ui:param/> tag, which exposes the value as a variable within the template.

When Facelets render the page above with the specified template, you will get the following output:

<!-- template.xhtml -->
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Sample Template</title>
</head>
<body>
   <h1>Here's my Title</h1>
   <div>Here's My Menu</div>
   <p>Here's My Body</p>

</body>
</html>

The previous example can be simplified even more if there's only one area that can be changed within a template:

<!-- simple-template.xhtml -->
   ...
<body>
   <h1>Title</h1>
   <!-- editable body -->
   <p><ui:insert/></p>
</body>
   ... 

The page that wants to use the above template can now be as simple as this:

<!-- simple-template-client.xhtml -->
   <ui:composition template="simple-template.xhtml">
   Here's My Simple Body
   </ui:composition>

Using Includes

The idea of compositions in pages is pretty powerful for defining re-usable content in your web pages. The examples so far have shown how to use compositions with a template for rendering. But what if you want to include that composition in another page? Maybe there's a series of form controls or a complex menu that you would rather separate out into a different document that can be reused or managed separately without cluttering up your page layout.

Facelets provides two ways of including compositions or other pages in general. The first option is with the <ui:include/> tag. This tag should be pretty familiar to web developers:

<!-- include.xhtml -->
   ...
   <span id="leftNav">
   <ui:include src="/WEB-INF/siteNav.xhtml"/>
   </span>
   ...
<!-- siteNav.xhtml -->
   ..
   <ui:composition>
   <!-- myfaces tomahawk components -->
   <t:tree2 value="#{backingBean.options}" var="opt">
   ...
   </t:tree2>
   </ui:composition>
   ...

When Facelets processes the include.xhtml, siteNav.xhtml will have all of its content within the <ui:composition/> included into include.xhtml:

<!-- include.xhtml -->
   ...
 <span id="leftNav">
   <!-- myfaces tomahawk components -->
   <t:tree2 value="#{backingBean.options}" var="opt">
   ...
   </t:tree2>
 </span>
 ...

If you would like to pass variables to siteNav.xhtml, to be used with the tree component, then you can use the <ui:param/> tag:

<!-- include.xhtml -->
   ...
 <span id="leftNav">
   <ui:include src="/WEB-INF/siteNav.xhtml">
   <ui:param name="menuBean" value="#{backingBean.options}"/>
   </ui:include>
 </span>
 ...
<!-- siteNav.xhtml -->
   ...
   <ui:composition>
   <!-- myfaces tomahawk components -->
   <t:tree2 value="#{menuBean}" var="opt">
   ...
   </t:tree2>
   </ui:composition>
   ...

You can see that now the siteNav.xhtml can just reference the variable menuBean and assume that it will be passed within the <ui:include/> tag. This allows for some flexibility with re-using common components and content.

Facelets provides an even cleaner solution to <ui:include/> and <ui:param/> by supporting custom tags. Don't worry, you don't have to write any Java code. To make siteNav.xhtml a reusable tag, you must create a simple XML taglib file:

<facelet-taglib>
   <namespace>">http://www.mycompany.com/jsf</namespace>
   <tag>
   <tag-name>siteNav.xhtml</tag-name>
   <source>/WEB-INF/tags/siteNav.xhtml</source>
   </tag>
</facelet-taglib>

Aside from pointing Facelets at your new taglib XML file, that's it. You may add as many tags as you want to your new taglib. By specifying the http://www.mycompany.com/jsf namespace within your pages, you can now write:

<!-- include-tag.xhtml -->
...

<span id="leftNav">
   <my:siteNav menuBean="#{backingBean.options}"/>
</span>
...

The include-tag.xhtml example is equivalent to the include.xhtml example above. The attribute menuBean will be made available as an attribute within siteNav.xhtml, just as <ui:param/> provided.

Your project may include a whole library of custom tags that are packaged with your JAR files or simply placed within a folder in your web application. Many more tags are covered in the Facelets Developer Documentation.



RSS feed(all feeds)

The Editor's Desk
Podcasts
Inside Facelets
In the Trenches

Site version 1.83  Report web site problems

Copyright (C) 2003-2014 Virtua, Inc. All Rights Reserved. Java, JavaServer Faces, and all Java-based marks are trademarks or registered trademarks of Oracle Corporation. in the United States and other countries. Virtua, Inc. is independent of Oracle Corporation. All other trademarks are the sole property of their respective owners.