Creating Custom Components with JSF and Facelets
Creating
custom components with JSF and Facelets is NOT the same as creating
custom JSF components with JSP. If you search on the internet for
custom JSF components you will get messed up, confused, and nothing is
seemingly clear. Its actually relatively easy to create a custom
component with Facelets relative to JSP. Allot less code is required
and only a few configuration files need to be modified/added.
There are four main steps in creating a custom component with JSF and Facelets.
- Create a facelet-taglib for your custom tag named something like myTags.taglib.xml . Also make sure this file is copied over to the EAR file in the META-INF directory. This is usually done through your build.xml under the target to build your EAR.
..
http://mystuff.com/mycomponent
mycomponent
com.mystuff.mycomponent
com.mystuff.components.mycomponent
- Next let JSF and Facelets know of your new component by adding it to /WEB-INF/faces-config.xml.
...
...
com.mystuff.mycomponent
com.mystuff.components.MyComponent
- Create the java code to render the component. To do this you need to remember a few things.
- Extend from the UIComponentBase class or any class that is a child of it.
- @Override getFamily , which should return the component type ( the same name as in he facelet-taglib and faces-config ).
- @Override encodeBegin and/or encodeEnd for outputting the componenet’s markup. Its good practice to use the response writer’s methods to start elements, add attributes to them, and to end elements.
- Provide getters and setters for your attributes.
- Be Careful!!!
If your component is used on a page with a form, and you throw exceptions for required values, then you must implement saveState and restoreState. If not the JSF lifecycle will try to recreate the component on the restoreView phase upon an invalid form entry. If not present the required exception is thrown since the value no longer exists.
-
public MyComponent(){
super();
setRendererType(null)
}
@Override
public String getFamily(){
return COMPONENT_TYPE;
}
@Override
public void encodeBegin(FacesContext context) throws IOException{
super.encodeBegin(context);
final ResponseWriter writer = context.getResponseWriter();
writer.write(""n");
writer.writeComment(" BEGIN MYCOMPONENT INCLUDE ");
writer.write(""n");
if(this.getRenderIncludes()){
String jsURL = context.getExternalContext().getRequestContextPath() + JS_DIR + "/" + JS_FILE;
writer.startElement("script", null);
writer.writeAttribute("type", "text/javascript", null);
writer.writeAttribute("src", jsURL, null);
writer.endElement("script");
writer.write(""n");
String jsURL2 = context.getExternalContext().getRequestContextPath() + JS_DIR + "/" + JS_FILE_2;
writer.startElement("script", null);
writer.writeAttribute("type", "text/javascript", null);
writer.writeAttribute("src", jsURL2, null);
writer.endElement("script");
writer.write(""n");
}
writer.startElement("script", null);
writer.write(""n");
writer.write("createMyComponentTag(");
writer.write("'" + getPageId() + "', ");
writer.write("'" + getTemplateId() + "', ");
writer.write("null, ");
writer.write("'" + getCategoryId() + "', ");
writer.write("null, ");
writer.write("null, ");
writer.write("null, ");
writer.write("null, ");
writer.write("null, ");
writer.write("null, ");
writer.write("null, ");
writer.write("null, ");
writer.write("null);"n");
writer.write(""n");
writer.endElement("script");
writer.write(""n");
writer.writeComment(" END MYCOMPONENT INCLUDE ");
}
@Override
public void encodeEnd(FacesContext context) throws IOException{
super.encodeEnd(context);
}
public String getPageId(){
if(null != this.pageId){
return this.pageId;
}
ValueExpression ve = getValueExpression("pageId");
if(ve == null){
throw new javax.el.ELException("Value for mystuff mycomponent Tag: 'pageId' is required");
}
return (String) ve.getValue(getFacesContext().getELContext());
}
public void setPageId(String pageId){
this.pageId = pageId;
}
- Now using your custom component is as easy as adding the namespace and adding the tag to your Facelet.
Other techniques for saving and restoring state, adding ajax functionality through phase listeners, and determining if you need to implement ActionSource, ValueHolder, or EditableValueHolder into your component can be searched on the internet. A good source of Facelets documentation is here https://facelets.dev.java.net/nonav/docs/dev/docbook.html .
Here is an example I added to show an easy custom component.
custom-pmc-ui1.zip
Its from the SEAM examples of the jboss-seam-2.0.2.SP1 release. Just add this to the examples folder of you SEAM directory.
Its path is “{SEAM_HOME}/examples/ui” . I’ve just added a package
called “org.mcjury.components”, a class for the component
“TableNameComponent.java”, a facelet called “tableName.xhtml”, an xml
file called “META-INF/table-component.taglib.xml”, and lastly edited
“faces.config.xml” to register the component.
The usage is followed by a couple of examples of my custom table component and a use of the entity-manager with a h:dataTable.
To deploy just run “ant” in the “examples/ui” folder. If you have
seam set up right it should copy over the EAR to you jboss server
deploy directory. The jboss home is set in your “build.properties” in
the root of the SEAM directory. If its not there just add this
“jboss.home=/PATH/TO/JBOSS/jboss-4.2.2.GA”
to it and you should be all set. Than start up jboss with “run.sh”.
Writing Custom Components in JSF + Facelets |
![]() |
![]() |
![]() |
Mar 20, 2007 at 03:27 PM | |
One of the misleading parts for me was that available articles treating
"custom JSF component creation" around are targetting JSF components
used within JSP pages. If you're using Facelets (a JSP independent
view-handler for JSF - see http://facelets.dev.java.net) things are
slightly different. At least it seems to be easier to create custom
components with Facelets than doing it with JSP. The encodeXXX-methods are used to render the component into HTML, the decode method is used to read the components selected value of the submitted form. I won't explain that in more detail here - look at the methods in the example above, it should be straightforward to understand. For more information about encoding and decoding refer to the JSF docs.
You can see that I've used a child component to assign the radio-groups select items but the |