This is a post about how to work with IDs in JavaServer Faces. You may find this useful if you want to use JavaScript with JSF.
Example ID developer sets on a JSF component: foo1 What JSF might render in the resultant HTML: j_id_jsp_115874224_691:table1:0:foo1
This is a revised version of JSF: working with component IDs (id vs clientId), though you don't need to read that. This post fixes some of the issues with the code, provides a more robust version of the library and details how to use it to make simpler, more reliable applications. The target JSF version is 1.2.
Topics
- Component identifiers versus client identifiers
- The (lack of) uniqueness of component identifiers
- The separator character
- Getting the clientId using component binding
- Sample code
- Recipe: reducing request map pollution with a utility resolver
- Recipe: avoiding binding collisions
- Recipe: editing table rows with JavaScript
- The client identifier in JSF 2.0
Component identifiers versus client identifiers
It is important to understand how IDs work if you're going to use them. Failure to do so may result in unexpected behaviour and make your application difficult to maintain.
So, why doesn't JSF just emit the ID you set on it?
Consider this dataTable
:
<h:dataTable id="d1" value="#{tableBean.rows}" var="row"> <h:column> <h:outputText value="#{row.name}" /> </h:column> <h:column> <h:inputText id="x1" value="#{row.quantity}" /> </h:column> </h:dataTable> <h:commandButton value="save" action="#{tableBean.save}" />
The table contains multiple, editable rows. In HTML, each of the
resultant input
controls requires a unique name
attribute. If you want to refer to the element by id
, each
row will need a unique ID. However, we only specify the control once in
JSF.
How the table might be rendered:
<table id="f1:d1"> <tbody> <tr> <td>beans</td> <td><input id="f1:d1:0:x1" type="text" name="f1:d1:0:x1" value="0" /></td> </tr> <tr> <td>carrots</td> <td><input id="f1:d1:1:x1" type="text" name="f1:d1:1:x1" value="0" /></td> </tr> <tr> <td>corns</td> <td><input id="f1:d1:2:x1" type="text" name="f1:d1:2:x1" value="0" /></td> </tr> </tbody> </table>
The component identifier is managed by the getId()/setId(String) methods and is automatically generated if the user does not set a value. The client identifier that appears in the browser is returned by getClientId(FacesContext) which may return different values for the same component depending on state managed by parent controls.
Any naming
container (such as a data
table component, or a form)
is responsible for managing the clientId
s of its children.
The clientId
may also be namespaced by the container (this
is done for portlet
views where multiple views may be rendered to a single HTML page).
The (lack of) uniqueness of component identifiers
The JSF specification says this about component identifiers:
If a component has been given an identifier, it must be unique in the namespace of the closest ancestor to that component that is a NamingContainer (if any).
This means that this view is legal even though two components
have an ID called x
:
<f:view> <h:outputText id="x" /> <h:form id="form1"> <h:outputText id="x" /> </h:form> </f:view>
UIForm
implements NamingContainer
and is responsible for namespacing its children. It would not be legal
to have both components with id="x"
inside or outside the
form.
The separator character
As we can see from examples like f1:d1:0:x1
, a colon
is used as a separator when building the clientId
. In JSF
1.2, this value comes from NamingContainer.SEPARATOR_CHAR,
but the exact value should be treated as an implementation detail. It
may be unwise to hard-code this value into your view code. (JSF
2 deprecates this field and allows developers to set the value via an
initialisation parameter keyed to javax.faces.SEPARATOR_CHAR
.)
Getting the clientId
using component binding
One of the better ways to get the clientId
is to
leverage component
bindings with a custom
tag library function.
<?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:id="http://illegalargumentexception.googlecode.com/clientId"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>clientIdTest</title> </head> <body> <h:form> <h:commandButton id="t1" binding="#{foo}" value="Hello, World!" onclick="alert('I am #{id:cid(foo)}'); return false;" /> </h:form> </body> </html>
The above Facelets page renders a single button that displays the
clientId
of the button when it is clicked. The component is
bound to the request scope map by the attribute binding="#{foo}"
.
In the JavaScript, the expression #{id:cid(foo)}
resolves
to the component's clientId
. This is how the button is
rendered:
<input id="j_id2:t1" name="j_id2:t1" type="submit" value="Hello, World!" onclick="alert('I am j_id2:t1'); return false;;" />
The custom tag library function resolves to this simple method:
public static String cid(UIComponent component) {
|
This function can be found in the sample code.
An alternate way to get the clientId
is to
bind the component to a request scope backing bean of some kind and then
expose a method that will return the clientId
from the
bound component. You swap writing a single custom function to managing
beans, though.
Sample code
A sample library implementing the functions described in this post can be downloaded here: clientId_2.0.1.zip
All the sources are available in a public Subversion repository.
Repository:
http://illegalargumentexception.googlecode.com/svn/trunk/code/java/
License: MIT
Project: JsfClientId
Recipe: reducing request map pollution with a utility resolver
If you need to get the clientId
(or other
properties) of multiple controls, you're faced with the prospect of
binding many controls to some backing source. This increases either the
amount of code you have to write or the likelihood that there will be a
naming collision with non-view artifacts. The Resolver
class allows you to find controls relative to each other.
<h:form binding="#{form1}"> <h:inputTextarea id="text1" cols="80" readonly="true" /> <br /> <h:inputTextarea id="text2" cols="80" readonly="false" /> <p>text1: <h:outputText value="#{id:resolver(form1).find['text1'].component.readonly}" /><br /> text2: <h:outputText value="#{id:resolver(form1).find['text2'].component.readonly}" /></p> </h:form>
In the above JSP code, only form1
is bound to a
backing resource. The resolver is used to locate the text controls and
read their readonly
attributes.
The resolver is just a wrapper class round component instances.
It provides other methods for finding parent containers, peers and
emitting clientId
s. All this can be done with the
equivalent static functions (and they are provided), but using the
resolver makes expressions less verbose. See the documentation for more
details.
Recipe: avoiding binding collisions
Binding to the request scope, as in the examples above, might be
convenient, but care needs to be taken to avoid duplicate bindings. For
example, if navigating between two pages, there is a danger that a
component in one view would end up in the other if they each had a
binding to #{requestScope.foo}
. That would be bad! If
you're making use of the component template features in Facelets, that
also increases the number of places you need to watch for collisions.
One way to get round this is to bind components to managed backing beans with a strict naming scheme. Another is to use a custom component to help, as in this Facelets code:
<id:resolver var="resolver1"> <h:outputText id="text1" value="Hello" /> <h:form id="form1"> <h:inputText id="text1" value="Goodbye" /> </h:form> <p>#{resolver1.find.text1.clientId} <br /> #{resolver1.find.form1.find.text1.clientId}</p> </id:resolver>
The resolver
component binds a Resolver
class instance (wrapping itself) to the request scope var
value much like a dataTable
binds its rows. If it detects a
collision, it will throw an exception. This code also
demonstrates how to cross a NamingContainer
boundary.
Recipe: editing table rows with JavaScript
Here's a HTML table with some buttons for setting quantities using JavaScript:
Here is the JSP page:
<?xml version="1.0" encoding="UTF-8" ?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:id="http://illegalargumentexception.googlecode.com/clientId" version="2.0"> <jsp:directive.page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" /> <jsp:text> <![CDATA[<?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">]]> </jsp:text> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JSF TABLE DEMO</title> <link href="style.css" rel="stylesheet" type="text/css" /> </head> <body> <f:view> <h:form id="f1"> <h:dataTable id="d1" value="#{tableBean.rows}" var="row"> <h:column> <h:outputText value="#{row.name}" /> </h:column> <h:column> <h:inputText id="x1" binding="#{foo}" value="#{row.quantity}" /> <h:commandButton value="+" onclick="setQuantity('#{id:cid(foo)}', 1); return false;" /> <h:commandButton value="-" onclick="setQuantity('#{id:cid(foo)}', -1); return false;" /> </h:column> </h:dataTable> <h:commandButton value="save" action="#{tableBean.save}" /> </h:form> </f:view> <script type="text/javascript"> <![CDATA[ function setQuantity(elementId, n) { try { var textField = document.getElementById(elementId); var value = parseInt(textField.value); textField.value = n + value; } catch(err) { alert(err); } } ]]> </script> </body> </html> </jsp:root>
The client identifier in JSF 2.0
JSF 2.0 adds the zero-argument getClientId()
method
to the UIComponent
class. A JSF 2.0 application could cut
out the function altogether; that is, #{id:cid(foo)}
could
be replaced with #{foo.clientId}
. Hey, no
custom code required!
JSF 2.0 also adds a few implicit variables to make resolving components easier.
<h:outputText id="foo" value="I am ${component.clientId}" />
This control will render something like I am foo
.
The implicit objects component
and cc
(composite control) are detailed in the spec (JSR 314).
JSF 2.0 will become part of Java Enterprise Edition in version 6, but it's open source, so you can go get it now if you want to.
Thanks for the useful article!
ReplyDeleteI would like to get clientId of multiple controls in JSF2.0.
Is there a simpler way in jsf 2.0 than using the resolver?
Does the technique you referred to at the end for JSF 2.0 actually work? I tried it and it doesn't work for me.
ReplyDeleteCan you elaborate with a working example or something?
Suggesting that the attribute `id` on the `inputText` component
creates an object that can be accessed with EL using `#{myInptTxtId}`,
in the above example. The article goes on to state that JSF 2.0 adds
the zero-argument `getClientId()` method to the `UIComponent` class.
Thereby allowing the `#{myInptTxtId.clientId}` construct suggested
above to get the actual generated id of the component.
Though in my tests this doesn't work. Can anyone else confirm/deny.
@Anonymous
ReplyDeleteThe last section on JSF 2.0 assumes you've followed the section on component binding.
Assuming #{myInptTxtId} resolves to a component binding, then #{myInptTxtId.clientId} (getClientId()) will resolve like any other getter as per the rules for EL.
Hi,
ReplyDeleteyou suggest in this section.
"An alternate way to get the clientId is to bind the component to a request scope backing bean of some kind and then expose a method that will return the clientId from the bound component. You swap writing a single custom function to managing beans, though."
can you give some example. thanks.
@Anonymous - see the IndexPageBean example here: http://illegalargumentexception.blogspot.co.uk/2009/02/jsf-working-with-component-ids.html#id_backingbean
ReplyDeleteI do not recommend this approach.