Because templates are not pages in themselves, we don't want them to be accessible as a page. In order to do this, we need to create it in the WEB-INF folder.
Note
The JEE7 standard stipulates that the WEB-INF folder and all of its contents must be inaccessible on a browser for users.
We need to keep things organized and place things such as template files separate from configuration files such as web.xml. So, we will create a folder named resources in the WEB-INF folder and then create another folder in the resources folder named templates. Perform the following steps to create a Facelets Template:
In the Projects navigator, open the WEB-INF folder and then select it. You should see something similar to the following screenshot:
Right-click on the WEB-INF folder, move the mouse over the New item, and select Folder..., as shown in the following screenshot:
Name the new folder resources. Next, create a new folder and name it templates. The WEB-INF folder should look similar to what's shown in the following screenshot:
We are now going to create a Facelets Template and modify it to remove the elements that we don't need. Right-click on the templates folder and move the mouse over the Facelets Template… item. If the Facelets Template… option is not visible, you will have to navigate to Other… | JavaServer Faces | Facelets Template….The dialog box that opens when you do this is shown in the following screenshot:
Call the chaptersTemplate template and leave the other options as they are with their default settings. When you open the template file or when NetBeans opens it for you, you will see the following code:
The page looks very much similar to the normal XHTML and in fact, it is a normal XHTML. What makes this usable as a template are the <ui:insert> tags. The JSF framework allows us to create pages based on a template, and define tags are used to replace the default content contained by the insert tags, with the content specific to the page. To illustrate this in a better way, we will now create a page that uses this template and runs the application so that we can see how this looks. After doing this, we will change the template to suit our needs.
To create the Facelets Template Client, right-click on the Web Files folder in the Project navigation, move the mouse over the New item, and select Facelets Template Client. The resulting dialog box is shown in the following screenshot. If the Facelets Template Client option is not available, then you will have to choose Other..., JavaServer Faces, and then select Facelets Template Client:
Call the index page. Then, select the template that you want to use by browsing for it. Click on the Browse button to the right of Template: and select the chaptersTemplate template that we created earlier.
Tip
If you already have an XHTML page called index, you will need to rename it first.
After clicking on Finish, NetBeans will open the newly create page to reveal the following code:
<?xml version='1.0' encoding='UTF-8' ?>
<!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://xmlns.jcp.org/jsf/facelets">
<body>
<ui:composition template="./WEB-INF/resources/templates/chaptersTemplate.xhtml"><ui:define name="top">
top
</ui:define>
<ui:define name="content">
content
</ui:define>
</ui:composition>
</body>
</html>
The composition tags tell the JSF framework that the following content replaces elements in the template. It also sets the template being used for this page.
The highlighted define tags have names, which match the insert tag names in the template. This is how the JSF framework builds pages using templates.
If you run the project, you will see the following in the browser:
As you can see, NetBeans has added some kind of theme to the page via the template. We can also see that the page title comes from the template and not the page itself. The changes that we are now going to make to the template will remove references to the CSS files that we are not going to use and add an insert component for a title.
We will also remove the div tags in the template that provide structure to the page, which is also not needed by us.
Open the chaptersTemplate file and remove the <h:outputStylesheet name="./css/cssLayout.css"/> tag. We also want to delete the cssLayout.css file, as we do not need it anymore.
Tip
JSF enables us to reference resources such as CSS and images without actually knowing where they are located. It does this by searching for the resources in special folders. These special folders are named resources and can be located either directly in the application's root folder or in the WEB-INF folder. It is no accident that we named the resources folder in WEB-INF the way we did.
NetBeans created default.css and cssLayout.css for us. Here, we see NetBeans applying best practices in that it separates structural and theme elements into cssLayout.css, which has rules that specify things such as the dimensions of containers, and default.css, which has rules that specify things such as fonts and foreground and background colors. PrimeFaces also applies this best practice, which makes creating custom themes much easier, as we will soon see.
Now, open the default.css file, select the entire contents, and delete it all, saving the file afterwards. In the title tag, add an insert tag with the name title. The default content should be Please add a proper title for this page!.
The changes that you have made so far should look like this:
<?xml version='1.0' encoding='UTF-8' ?>
<!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://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<h:outputStylesheet name="./css/default.css"/>
<title>
<ui:insert name="title">Please add a proper title for this page!</ui:insert>
</title>
</h:head>
<h:body>
<div id="top" class="top">
<ui:insert name="top">Top</ui:insert>
</div>
<div id="content" class="center_content">
<ui:insert name="content">Content</ui:insert>
</div>
</h:body>
</html>
If you now save the template and refresh the page in the browser, you will see something similar to the following screenshot:
By removing the reference to the cssLayout.css file and emptying the default.css file, you changed how the page looks. The background colors are gone, and the font used is the browser default, which is usually Times New Roman.
Although you haven't added a title using a define tag for the index.xhtml file, the default content from the template is used. Now, open the index.xhtml file and add a define tag, whose content should be Welcome to Developing PrimeFaces Themes.
The code now looks like this:
<?xml version='1.0' encoding='UTF-8' ?>
<!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://xmlns.jcp.org/jsf/facelets">
<body>
<ui:composition template="./WEB-INF/resources/templates/chaptersTemplate.xhtml">
<ui:define name="title">Welcome to Developing PrimeFaces Themes</ui:define>
<ui:define name="top">
top
</ui:define>
<ui:define name="content">
content
</ui:define>
</ui:composition>
</body>
</html>
The page title code that we added is highlighted. Note that it is not important where the define tags are placed. The only important thing that you need to remember is that they must be contained by the composition tag. When you save the page and refresh it in your browser, you will see something similar to the following:
Now, go back to the Facelets Template and replace its contents with the following code:
The view tag is used to instruct the browser about the type of content for the page and its character encoding.
Tip
The view tag isn't strictly needed. However, some browsers will not display certain content correctly if we don't use it. Hence, we use it here. It should be used in every JSF page for every JSF project. Remember that it also needs to enclose the head and body tags of the page.
The facet tag with the name="last" attribute tells PrimeFaces where to generate the HTML code for the CSS file reference in the head section of the page after any others that JSF and/or PrimeFaces generates.
The <h:outputStylesheet library="css" name="default.css"/> tag loads the default.css file from the CSS library. The Oracle JSF Tutorial explains what this means in detail. Basically, folders in a resources folder are treated as libraries of resources. Hence, we used library="css" and name="default.css".
Tip
The JSF specification does not specify which order resource references such as this are to be in the page. This means that PrimeFaces-generated resource references can appear before or after the ones that we use in our pages. This makes using the cascading part of CSS impossible. To solve this problem, PrimeFaces takes over the responsibility of generating the resource reference HTML from JSF and allows us to specify the order in which our references should be generated in relation to those that PrimeFaces and other component libraries generate. The order is specified using facets with the name="last" or name="first" attributes.
We added navigation elements to the template. Active elements like this need to be contained by a form tag. The ThemeSwitcher component also needs to be contained within a form.
Because this is a book about PrimeFaces themes, it is only right that we use the PrimeFaces navigation component named menubar. Contained within the menubar is a menuitem, which links to the start page of our project and a submenu for Chapter 2. At this point, the Chapter 2 submenu only contains one link to the differences.xhtml page. By default, the menu bar aligns its child elements to the left.
The <f:facet name="options"> tag allows us to add components to the right of the menubar. Inside this facet, we have two outputText tags, which set the Current theme label and the name of the theme that is currently selected by the user.
Also contained in this facet is the ThemeSwitcher component as well as the selectItem and selectItems tags that configure it.
If you look at the outputText tag, which displays the name of the currently selected theme, its value attribute contains code similar to the code used in web.xml to set the current theme for the application.
This is no coincidence. EL (short for Expression Language) expressions are used to wire up the frontend of an application (the pages) with the Beans that we use in the application's middle layer.
Note
One of the biggest problems with the JSP framework was that it allowed developers to mix server-side business logic with the display elements in the code. This led to a project that was very hard to maintain and it also meant that web developers and the developers who write the business logic occupied the same real estate as it were. JSF now makes this impossible by not allowing any server-side code to be embedded in the page, forcing the Beans developers and the web developers apart. This not only makes for more easily maintainable projects, but also means that Beans developers who don't require knowledge of the frontend can maintain code that is separate from the web developers who don't need any knowledge of Java at all. The glue that allows you to bind properties and method calls for AJAX requests is EL. A complete explanation of EL expressions and JSF is beyond the scope of this book. Oracle published a JSF 2.2 tutorial, which can be found at https://docs.oracle.com/javaee/7/tutorial/.
After saving the template, you can now go back to the index.xhtml file and simply remove the define name="top" tag and its contents. Save your changes and then refresh the page in the browser. With luck, you will see something similar to the following screenshot:
If the page doesn't looks like this or it doesn't appear at all, you may need to clean and build the project before running it again.
The ThemeSwitcher component to the right of the page can now be used to change the theme being used. Here is a screenshot, with the le-frog theme selected:
You may have noted that changing the theme does not require the entire page to be reloaded. The magic happens in the browser with a small AJAX request, which causes the value for the theme property in the CurrentTheme Bean to be set and another one, which updates the navigation section of the page. Because we only have the word content in the content section of the page, the savings in network traffic are not very big, but imagine a page with a lot of components and displayed information in the content section of the page.
As you can see, you managed to build in some rather complicated features into the pages with minimum effort. JSF is a very powerful technology in itself, and one of the most powerful features is its extensibility. The PrimeFaces developers used this extensibility to provide us with a component library that makes adding these otherwise complicated features easy.
We are now going to create a page based on chaptersTemplate in the chapter2 folder.
Then, we are going to add several PrimeFaces components to this page so that we can demonstrate how things look across several themes. Last but not least, we are going to add three buttons and make those buttons change the current theme without using the ThemeSwitcher. We are also going to add a link to that page in chaptersTemplate, clean and build the project, and run it anew.