Rather than using includes when creating templates you can create your own custom facelet tags without the husle of creating a JSF component from scratch. As an example, I'll create a menu tag that can be used to switch a selected menu item on and off.
Here is the menu (save it as /WEB-INF/facelets/tags/menu.xhtml
):
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<h:panelGrid columns="10">
<h:outputText styleClass="menuItem" value="Home" />
<h:outputText styleClass="menuItem" value="Some page" />
<h:outputText styleClass="menuItem" value="Another page" />
<h:outputText styleClass="menuItem" value="Third page" />
</h:panelGrid>
</ui:composition>
Here is the cascanding style sheet:
.menuItem {
border: 1px solid black;
}
.menuItemSelected {
background: red;
color: white;
font-weight: bold;
}
To make the menu into a tag you create a facelets tag library. I'll call it
mytags.taglib.xml
and place it in /WEB-INF/facelets/
:
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://bigallan.blogspot.com/mytags
<tag>
<tag-name>menu</tag-name>
<source>tags/menu.xhtml</source>
</tag>
</facelet-taglib>
To make the web application recognise your tag library you need to update add the following context parameter to
web.xml
:
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/facelets/mytags.taglib.xml</param-value>
</context-param>
If you have more than one custom tag library you can separate them with semicolons (;)
On your pages you can now include the menu tag:
<?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://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:mytags="http://bigallan.blogspot.com/mytags">
<head>
<title>My page</title>
<link href="css/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<mytags:menu home="true" />
</body>
</html>
All we need to do now is to look out for the attributes of the custom tag. Attributes are automatically turned into variables on the tag pages, so we simply make the following changes to
/WEB-INF/facelets/tags/menu.xhtml
:
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<h:panelGrid columns="10">
<h:outputText styleClass="menuItem #{home == 'true' ? 'menuItemSelected' : ''}" value="Home" />
<h:outputText styleClass="menuItem #{somePage == 'true' ? 'menuItemSelected' : ''}" value="Some page" />
<h:outputText styleClass="menuItem #{anotherPage == 'true' ? 'menuItemSelected' : ''}" value="Another page" />
<h:outputText styleClass="menuItem #{thirdPage == 'true' ? 'menuItemSelected' : ''}" value="Third page" />
</h:panelGrid>
</ui:composition>
To turn all menu items on you code do the following:
<?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://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:mytags="http://bigallan.blogspot.com/mytags">
<head>
<title>My page</title>
<link href="css/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<mytags:menu home="true" somePage="true" anotherPage="true" thirdPage="true" />
</body>
</html>
Enjoy!
Suggested reading on the subject:
11 comments:
Hi,
Nice blog.
Thanks,
Guddu
http://freesourceutilityhelp.googlepages.com
Hi,
Great example!
I was wondering if there is any way to document the tag's attributes?
So far I've read that there is no possibility to scan the facelet, so I'm expecting some other solution.
You are right that there is no way of scanning a faclets file to determine the tag attributes, as any variable in the file could be a tag.
Instead you could document the tag by creating a TLD (Tag Library Descriptor) for the facelet file and then run it through a utility like taglibdoc which creates JavaDoc-like documentation for tag libraries.
Hi,
I tried ur example but my page displayed blank . The source code of the xhtml showed the tag as it was written , it was not replaced.
It means the tag was not recognised. Any inputs ?
Sounds like you missed the step of loading your tags into Facelets using the context parameter facelets.LIBRARIES.
Hi Allan,
Thanks for the prompt reply . But I have done that too. I have the entry in web.xml
Any other specific thing like should all the xxx.taglib.xml files be inside facelets folder only ?
You can place the taglib.xml files in any directory of the web application. If you have more than one Facelets taglib you should separate them using semicolons (;) and not commas (,).
Also check that the namespace is identical in both the taglib.xml and the XML namespace declaration on the XHTML page.
Hi Allan,
It worked , I copy pasted into some running code and it worked fine.
I have on more problem though not related with your issue .
I have an existing project which uses Myfaces and JSP . I have a custom Pagination tag in the project which works fine.
The tag is extending the org.apache.myfaces.taglib.core.ViewTag and has doStart and doEnd methods. For this tag there is a tld and which I have included in the jsp :
%@ taglib uri="/WEB-INF/PaginationTag.tld" prefix="p" %
This is my tag class :
public class PaginationTag extends ViewTag {
public int doStartTag(){
......
}
}
I havent made any other entry in faces-config or made any renderer/component for this tag.
I am trying to create the same tag in SUN JSF RI 1.2 and Facelets . But the tag doesn't seem to work . there is not error thrown but the xhtml file doesnot seem to understand the tag and it displays the tag as it is.
I have extended the com.sun.faces.taglib.jsf_core.ViewTag to create this tag since I am using SUN JSF RI 1.2 .
Do I need to create a Component class and/or a Renderer too . Why it was not required in myfaces case ?
How can I have the same functionality as I had in the JSP case like implement doStartTag() and other methods ?
Please help me some links or example codes you have ?
Also which books one should refer for Facelets and JSF ?
For custom tags you will need to provide Facelets with a taglib.xml like the one you created for this example.
An example of such a taglib.xml can be found on the MyFaces wiki where they are explaining how to get the Tomahawk JSF library to work with Facelets.
I can highlighly recommend The Facelets Essentials book from Apress written by my good friend Zubin Wadia.
Hi,
When i am giving home="true" only then other menus are displaying but without css. Is it possible that they should not be visible if the are not true?
Thanks for Reply.
Hi there,
home="true" should display the Home link with red background and white text, and the other links should be ordinary links. Ensure that you don't have any break lines in the lines of h:outputText. On the blog entry the lines may appear to be chopped into separate lines when each h:outputText is suppose to have only a single line.
P.S. The blog is being moved to http://blogs.i2m.dk/allan.
Post a Comment