Tuesday, April 18, 2006

Setting focus on input fields with JSF and Facelets

JavaServer(tm) Faces components have a dynamic id. This can create problems when trying to access these components from JavaScript code on the client. I my case I wanted to do a very simple and common thing, set input focus on a specific field. One solution is to use a custom component called IDProxy (http://www.jsftutorials.net/proxyTag.html). This component makes it easy to obtain the dynamic generated id for it's parent element. While I found lots of articles on Internet explaining the use of IDProxy with JSF, I found no article that used Facelets as the rendering technique. Facelets (https://facelets.dev.java.net/) is a powerful templating system that allows you to define JSF views using HTML-style templates. In this article I will explain how I used IDProxy to set focus on an input field rendered with Facelets.

Download j4j.jar and put it in the WEB-INF/lib folder of your web project. Create a file called j4j.taglib.xml in the META-INF folder of your web project. The file should look like this:

<?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://javascript4jsf.dev.java.net/</namespace>
<tag>
  <tag-name>idProxy</tag-name>
  <component>
    <component-type>org.j4j.idProxy</component-type>
  </component>
</tag>
</facelet-taglib>

Add the j4j namespace to the xhtml page where you want to use idProxy.

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:j4j="http://javascript4jsf.dev.java.net/">

Add an idProxy tag inside the input element that you want to get the dynamic id from. In my case I want to get the dynamic id of a field called username in a login dialog.

<h:outputlabel for="username">Username</h:outputLabel>
<h:inputtext id="username" value="#{user.username}">
<j4j:idproxy id="_focus"/>
</h:inputText>

Now you can extract the dynamic id through the idProxy element from JavaScript code. The title property of the idProxy element contain the generated id of it's parent element, that's the value we want.

<script language="javascript">
//<![CDATA[
var iid=document.getElementById("_focus");
if(iid != null) {
document.getElementById(iid.title).focus();
}
//]]>
</script>

If you put the JavaScript code in your facelets template, you just have to include the j4j namespace declaration and the idProxy tag in each page where you want to set focus on a field.

This works great for me, but I'm still puzzled... Why is such a common thing like setting focus not standardized in JSF?

2 comments:

Klaus said...

Hi! Thanks for the really good information! I made my defaultAction with facelets with the own tag library. thanks a lot!
Here is my history of the problem inclusive the resulution:
http://www.coderanch.com/t/430486/JSF/java/J-J-Tag-Library-rendering

Unknown said...

Hi. Could you post the expected result (HTML) when you use the taglib inside a text component? I'm asking because I was not able to see the ID(eg. "_focus"). Thanks!