Creating pages based on a JSF template: Using the Facelets ui:define tag

What do you do once you've set up a handsome page template using the Facelets functions that come with JSF 2.x? Well, you start creating new pages, meshing those ui:define tags in with ui:composition and ui:insert. It's easier than it sounds, trust me.

If you're interested in creating an enterprise application using Facelets as your template engine, there's a couple of initial tasks that need to be accomplished:

  1. You need to create a basic page using HTML and CSS that defines what your various web pages are going to look like (We did this in Tutorial I)
  2. You need to identify the various parts of the page that represent unique content spots and decorate those content spots with ui:insert tags (We did this in Tutorial II)

The layout.xhtml page

These aforementioned tasks have already been accomplished, and our completed template, saved in a file named layout.xhtml, reads as follows:

<html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
	<link href="stylesheet.css" rel="stylesheet" type="text/css" />
</h:head>
<h:body>
	<div id="page">
		<div id="header-container">
			<div id="header">
				<ui:insert name="header">
					<p>Header</p>
				</ui:insert>
			</div>
		</div>
		<div id="messages-container">
			<div id="messages">
				<ui:insert name="messages">
					<p>Messages</p>
				</ui:insert>
			</div>
		</div>
		<div id="content-container">
			<div id="content">
				<ui:insert name="content">
					<p>Main content</p>
				</ui:insert>
			</div>
			<div id="sidebar">
				<ui:insert name="rightnav">
					<p>Sidebar/Right-nav</p>
				</ui:insert>
			</div>
		</div>
		<div id="footer-container">
			<div id="footer">
				<ui:insert name="footer">
					<p>Footer</p>
				</ui:insert>
			</div>
		</div>
	</div>
</h:body>
</html>

Template based development with Facelets and JSF 2.x

With the template completed, the next step is to create new pages based upon it, with each new page replacing what is displayed in the content area with something a little more engaging for the user. The header, footer, message area and right-nav sections will remain constant. As the user navigates from page to page, only the content section, currently displaying the words Main content, as shown in the image below, is going to change. Here's what the web page currently looks like when you pull up the layout.xhtml page in a browser like Google Chrome or Mozilla's Firefox:

The application flow

Initially, our application is only going to have three pages in it, and those pages won't even use any JSF tags. Only the templating tags provided by the Facelets engine are going to be used right now in an effort to keep our focus exclusively on Facelets development. We are just going to flush out the templating task, make sure we can navigate from one page to the next, and not complicate anything with any user input or dynamic interactions. We'll get there later, but there's no reason to complicate the Facelets work with JSF work for now.

In our scenario, we are going to ask the user two questions:

1. What is your name?

2. In what year were you born?

And after that, there will be a summary page. If you're keeping count, you'll see that the application has three simple xhtml pages:

  1. step01_name.xhtml
  2. step02_birthday.xhtml
  3. step03_completed.xhtml

The ui:define tag

The first page in our application will simply ask the user their age, with this question going in the content area of the page based on the recently created layout. So how do we create a new web page that will inject new information in only the content area of our template? To answer that question, first look at the layout.xhtml template page. The template includes the following ui:insert tag, identifying a display spot with the name attribute initialized to the value of content:

<ui:insert name="content">
  <p>Main content</p>
</ui:insert>

Leveraging this ui:insert spot, we can create a new page, named step01_name.xhtml, and override what currently appears in the display spot named content. We do this by first using a ui:composition tag and pointing to the template page named layout.xhtml:

<ui:composition template="layout.xhtml">
</ui:composition >

Within these ui:composition tags, we inject new markup. We do this by using the ui:define tag and specifying the name attribute used by the ui:insert tag in the template.

<ui:composition template="layout.xhtml">
	<ui:define name="content">

		<p>What is your name?</p>
		<p><a href="step02_birthday.xhtml">Next</a></p>
				
	</ui:define>
</ui:composition>

When this page runs, the new content, asking for a name and linking to the second, soon to be created page, will be displayed.

The step01_name.xhtml in full

Of course, every JSF page must be well formed, so there is a need to include all of the HTML, HEAD and BODY tags in the page. The full step01_name.xhtml page looks as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head></h:head>
<h:body>
<ui:composition template="layout.xhtml">
	<ui:define name="content">

		<p>What is your name?</p>
		<p><a href="step02_birthday.xhtml">Next</a></p>
				
	</ui:define>
</ui:composition>
</h:body>
</h:html>

The step02_birthday.xhtml page

The second page, step02_birthday.xhtml, is very similar, with only the content to be displayed to the user changing:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head></h:head>
<h:body>
	<ui:composition template="layout.xhtml">
		<ui:define name="content">

				<p>What year were you born?</p>
				<p><a href="step03_completed.xhtml">Next</a></p>

		</ui:define>
	</ui:composition>	
</h:body>
</h:html>

The step03_completed.xhtml page

And by time you get to the final page, you're probably so good at working with Facelets, you're probably getting bored with the whole process:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<h:html xmlns="https://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head></h:head>
<h:body>
	<ui:composition template="layout.xhtml">
		<ui:define name="content">
			<p>Thanks you for the information.</p>
		</ui:define>
	</ui:composition>	
</h:body>
</h:html>

And that's all there is to it! To create a template based application, Facelets makes the process incredibly easy. All you have to do is create your template and then create new pages based upon it. Just use the ui:define tags to inject new content into the area of interest, and you can easily create a site with a consistent and easy to maintain look and feel.

Integrating dynamic JSF content with a Facelets template

Of course, right now our content is completely static. We are using the Facelets template engine properly, but sadly, we're not using JSF at all. That's what we'll do in the next tutorial; we'll throw some JavaServer Faces 2.2 tags into our Facelets pages and work in some managed beans as well. That way we'll have the best of both worlds, that is, Facelets as the template engine and JSF providing dynamic, server-side interactivity.

 

What is your favorite Java based template engine? Let us know.

You can follow Cameron McKenzie on Twitter: @potemcam

 

 

 

Dig Deeper on Front-end, back-end and middle-tier frameworks