As you probably know, Dojo Toolkit is an "open-source JavaScript toolkit useful for building great web applications". In this recipe, you will see how to mix Dojo and JSF to create a custom component. JSF comes with a custom component that has a text field for entering e-mail addresses, while Dojo comes with e-mail validation and will add a few styles to our component.
We have developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library.
In addition, you have to download Dojo, which is available at the address www.dojotoolkit.org or in the book code bundle under the /JSF_libs/Dojo JSF 2.0
folder. Dojo can be extracted in a folder named /script
, next to the /WEB-INF
folder of your project.
We start with the page itself. This page will import Dojo libraries, and will give an example of using the custom component:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://packt.net/cookbook/components" prefix="e" %> <style type="text/css"> @import url("${pageContext.request.contextPath} /script/dojo_lib/dijit/themes/nihilo/nihilo.css"); @import url("${pageContext.request.contextPath} /script/dojo_lib/dojo/resources/dojo.css"); </style> <script type="text/javascript" src="${pageContext.request.contextPath}/script/dojo_lib/dojo/dojo.js" djConfig="parseOnLoad: true, isDebug:false"> </script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.require("dijit.form.ValidationTextBox"); dojo.require("dijit.form.Textarea"); </script> <body class="nihilo"> <f:view> <h2>JSF and Dojo working for great custom components</h2> <h:form id="emailFormID"> <h:outputText value="Provide your e-mail:" /> <e:input id="emailID" type="text" promptMessage="Provide your e-mail!" invalidMessage="Invalid e-mail!" dojoType="dijit.form.ValidationTextBox" dojoRequired="true" regExp="[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}" value="#{dojoEmailBean.email}"/> <h:commandButton id="emailBtnID" action="response.jsp" value="Submit" type="submit"> </h:commandButton> </h:form> </f:view> </body>
As you can see the component is named input
and it has a set of attributes specific to Dojo components (promptMessage, inputMessage, dojoType, dojoRequired
, and regExp
).
Next, you have to develop two classes that you are already familiar with. The first one is the tag handler class, listed next:
package custom.component; import com.sun.faces.taglib.html_basic.InputTextTag; import javax.faces.component.UIComponent; public class UIEmailInputTag extends InputTextTag { @Override public String getComponentType() { return "javax.faces.HtmlInputText"; } @Override public String getRendererType() { return "jsf.dojo.render"; } private String promptMessage; private String invalidMessage; private String dojoRequired; private String regExp; private String dojoType; private String type; public String getPromptMessage() { return promptMessage; } public void setPromptMessage(String promptMessage) { this.promptMessage = promptMessage; } public String getInvalidMessage() { return invalidMessage; } public void setInvalidMessage(String invalidMessage) { this.invalidMessage = invalidMessage; } public String getDojoRequired() { return dojoRequired; } public void setDojoRequired(String dojoRequired) { this.dojoRequired = dojoRequired; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getRegExp() { return regExp; } public void setRegExp(String regExp) { this.regExp = regExp; } public String getDojoType() { return dojoType; } public void setDojoType(String dojoType) { this.dojoType = dojoType; } @Override protected void setProperties(UIComponent component) { super.setProperties(component); component.getAttributes().put("promptMessage", promptMessage); component.getAttributes().put("dojoRequired", dojoRequired); component.getAttributes().put("invalidMessage", invalidMessage); component.getAttributes().put("type", type); component.getAttributes().put("dojoType", dojoType); component.getAttributes().put("regExp", regExp); } }
The second is the renderer class. Again, we have a common renderer (nothing special):
package custom.component; import javax.faces.component.UIComponent; import javax.faces.component.ValueHolder; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.component.UIInput; import com.sun.faces.renderkit.html_basic.TextRenderer; import java.io.IOException; public class UIEmailInputRender extends TextRenderer { @Override public void encodeEnd(FacesContext ctx, UIComponent ui_comp) throws IOException { ResponseWriter responseWriter = ctx.getResponseWriter(); responseWriter.startElement("input", ui_comp); String id = (String) ui_comp.getClientId(ctx); responseWriter.writeAttribute("id", id, "id"); responseWriter.writeAttribute("name", id, "id"); responseWriter.writeAttribute("value", getValue(ui_comp), "value"); responseWriter.writeAttribute("type", (String) ui_comp.getAttributes().get("type"), null); responseWriter.writeAttribute("invalidMessage", (String)ui_comp.getAttributes().get("invalidMessage"),null); responseWriter.writeAttribute("regExp", (String) ui_comp.getAttributes().get("regExp"), null); responseWriter.writeAttribute("dojoType", (String) ui_comp.getAttributes().get("dojoType"), null); responseWriter.writeAttribute("required", (String) ui_comp.getAttributes().get("dojoRequired"), null); responseWriter.writeAttribute("promptMessage", (String)ui_comp.getAttributes().get("promptMessage"), null); responseWriter.endElement("input"); } @Override protected Object getValue(UIComponent ui_comp) { Object objValue = null; if (ui_comp instanceof UIInput) { objValue = ((UIInput)ui_comp).getSubmittedValue(); } if ((objValue == null) && (ui_comp instanceof ValueHolder)) { objValue = ((ValueHolder) ui_comp).getValue(); } if (objValue == null) { objValue = ""; } return objValue; } }
Finally, you need to write the TLD file for the input
component (not listed here), configure the renderer in faces-config.xml
, and write the DojoEmailBean
, which is a trivial bean. You can see both these tasks accomplished in the complete example.