Creating custom components can really clean up your faces pages and keep you from repeating yourself over and over. And its fun to do! There are a number of posts out there and tutorials about creating custom components, and often times they leave out the most important pieces of configuration. In this post I will specify how to create composite components with Facelets. This is different from the jsf style custom components in that these are much easier to create, require much less configuration, and often times solve the problem at hand very quickly.
The Affected files
- the Web Descriptor
- The component definition
- The tag library descriptor
- The pages that you insert the component into
The Web descriptor, (web.xml) tells your container about your tag lib descriptor file.
The component definition fie specifies how the component is laid out. It may have logic in it and you may pass parameters to it. It produces the markup that appears in your faces page.
The Tag Library descriptor is an xml file that describes to the container what to do when it encounters your custom component tag.
Finally, your pages need to include the tag for it to be seen.
Getting Started
The first thing to do when creating a component is to generate the markup, styling and any scripts that accompany it in a sandbox. Try inserting it in your pages and seeing what it looks like and get it to work correctly. Once this is done, you are ready to generate the reusable tag that will display your component each time you need it. In this case I made a progress bar for my application.
Directory Layout
Under WEB-INF, create a directory called facelets, with a sub directory called tags.
In the tags directory we are going to place our tag library decriptor and our component.
myProject.taglib.xml
The Tag Lib Descriptor file: (myProject.taglib.xml)
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://www.yourId/jsf</namespace>
<tag>
<tag-name>progress</tag-name>
<source>progress.xhtml</source>
</tag>
</facelet-taglib>
The file specifies the following items:
namespace - Your unique id that wont conflict with other known urls. It does not need to exist on a server, it just needs to be unique. In this example I called it http://yourId/jsf. Any components that you place in this tag lib descriptor will be accessed in you pages using this as the uri to find this definition file. So in your pages that contain the component, the following tag will be added in your opening definitions:
xmlns:xx="http://www.yourId/jsf"where xx will be the tag handle in the page.
tag-name is the name of this particular component. In this case it is a progress bar. In your page you will access it via xx:progress
source is the name of the file that we will create to define our tag - the markup.
web.xml
Now we need to tell the application about our library. In web.xml, create the following entry:
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/facelets/tags/myProject.taglib.xml</param-value>
</context-param>
If you already have an entry like this, the param values can be a semi-colon delimited list.
progress.xhtml
So now we have our tag lib descriptor, and the container knows about it. Lets generate the component file. The name of the file must match the name in the taglib descriptor for the component. It is the source tag. So when the application encounters the tag name in the page, it looks up in the taglib descriptor (which it gets from the namespace definition) and finds the source file associated with the tag name.
This file also resides in WEB-IN/facelets/tags.
The file:
<!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"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<ui:composition>
<span class="progressContainer" >
<div class="progressBar" >
<c:if>
...more markup
</c:if>
</div>
</span>
</ui:composition>
</html>
I've left out my markup, but you can put yours in. We will look at parameter passing a bit later. For now, lets just get you using a tag in your pages. At this point everything is set to go. You just need to include the definition for your library in your page, and then specify the tag in the page.
So in your page:
In the opening tag, include the definition:
xmlns:xx="http://www.yourId/jsf"
Note that this must match the namespace specified in your tag lib descriptor. Remember that this is an arbitrary name for id purposes only. The xx is an arbitrary handle for accesing the library in your page.
Then, in your page to use the tag you would call:
<xx:progress/>
OK So at this point the tag should appear in your pages where you specify it. In the next edition, we will discuss parameter passing and using jstl in the tags. I also like to include certain tags in my templates that pages use. This requires a different approach for parameter passing, as the template defines where the tag will be, but the pages may want to use the tag differently.
Hope that helps.