Robert has posted 4 posts at DZone. View Full User Profile

Jsf 2.0 ClientId with jQuery

02.23.2011
| 25726 views |
  • submit to reddit

 In this article I will show how to work with the clientId property of UIComponent, which has been improved in JavaServer Faces 2.0, about finding concrete id from client side and how to use this knowledge with jQuery library. We will examine Composite Components, Facelets Composition , Facelets Templating and UIComponents with NamingContainer (for example UIData).

Pre-requirements 

In this article I used NetBeans 6.9 IDE, Mojarra 2.0.2 (FCS b10) as JSF 2.0 implementation and GlassFish 3.0.1.

Hello ClientId

 In this step we will create our first simple web application with only one page.

 1.From the NetBeans wizard choose Java Web -> Web application ->ClientIdExampleApp -> Select EE 6 Web and Glassfish 3 -> Select JavaServer Faces Framework (with Facelets View ) and click finish. 

Receiving ClientId from new JSF 2.0 ${component} EL Expression

<h:form id="form1" prependId="true">
${component.clientId}
<h:commandButton id="btn1" value="${component.clientId}" />
${component.clientId}
<h:panelGroup id="panel1" layout="block">
${component.clientId}
</h:panelGroup>
</h:form> 

 That code should produce something like that:

<form enctype="application/x-www-form-urlencoded" action="/WebApplication1/faces/index.xhtml" method="post" name="form1" id="form1">
(1)form1
<input type="submit" (2)value="form1:btn1" name="form1:btn1" id="form1:btn1">
(3)form1
<div id="form1:panel1">
(4)form1:panel1
</div>
</form>

 Although this example is really easy to code we can see that:

${component.clientId} returns the "nearest" parent UIComponent. Points (2) and (4) resolved clientId properly while (1) and (3) resolved clientId of parent: UIForm . If we need to create javascript function this solution is really quick and good enought. On the other hand when we need to have cross page javascript id reference better aproach is to use binding attributes.

Receiving ClientId from binding attributes of UIComponents

 The second way is more complicated but is more effective in various cases. Two steps are needed to get the clientId by binding. First we need to add binding attribute and connect this attribute with Managed Bean property corresponding to the particular UIComponent subclasses.

 Simple form:

<h:form id="form1" prependId="true" binding="(1)${index.form1}" style="background-color: red">
ClientId: (2)${index.form1.clientId}<br />
Simple attribute of form1: (3)${index.form1.attributes["style"]}<br />
<h:commandButton id="btn1" value="(4)#{index.form1.findComponent('btn1').clientId} :-)" />

<h:panelGroup id="panel1" layout="block">
(5)${component.clientId} <br />
</h:panelGroup><br />
panel1 clientId: (6)#{index.form1.findComponent("panel1").clientId} <br />
panel1 layout attribute (7)#{index.form1.findComponent("panel1").attributes["layout"]}
</h:form>
  Java managed bean code:
@ManagedBean
@RequestScoped
public class index {

private UIForm form1;

public UIForm getForm1() {
return form1;
}

public void setForm1(UIForm form1) {
this.form1 = form1;
}

public index() {
}
}
 Rendered html:
<form style="background-color: red;" enctype="application/x-www-form-urlencoded" action="/WebApplication1/faces/index.xhtml;jsessionid=64e609789a8d90f6993151f964d4" method="post" name="form1" id="form1">
ClientId: form1<br>
Simple attribute of form1: background-color: red<br /><input type="submit" value="form1:btn1 :-)" name="form1:btn1" id="form1:btn1"><div id="form1:panel1">
form1:panel1 <br /></div><br />
panel1 clientId: form1: panel1 <br />
panel1 layout attribute: block
</form>

 Short clarification

 In points: (1),(2),(3) and (5) we used a dollar sign $ to access the properties (form1 and component) of the managed bean. In (4),(7),(6) we used the hash sign # to refer UIComponent methods like findComponent to find child component and uses panel1 properties. 

ClientId with NamingContainer

Now I will add some examples of my web application and explain how does it all work. Let start with h:dataTable with few rows and two columns. The second column will contain a h:commandButton and we want use this button to do some client Javascript action.

 Here is a simple datatable:

<h:dataTable id="dt1" binding="${clientIdExample.dt1}" value="#{clientIdExample.localeList}" var="item"
dir="LTR" frame="hsides" rules="all" summary="This is a JSF code to create dataTable." >

<f:facet name="header">
<h:outputText value="This is 'dataTable' demo" />
</f:facet>
<h:column id="col1">
${component.clientId}
<f:facet name="header">
<h:outputText value="name"/>
</f:facet>
<h:outputText value="#{item.displayName}" style="margin:5px; padding:5px"></h:outputText>
</h:column>
<h:column id="col2">
<f:facet name="header">
<h:outputText value="click"/>
</f:facet>
<h:commandButton id="editRow" value="click" onclick="toggleRow('${component.clientId}');return false;"
style="margin:5px; padding:5px"/>
</h:column>
<f:facet name="footer">
<h:outputText value="The End" />
</f:facet>
</h:dataTable>
And of course our ManagedBean:
@Named(value = "clientIdExample")
@RequestScoped
public class ClientIdExample {
private Locale[] localeList;
private HtmlDataTable dt1;

public Locale[] getLocaleList() {
Locale[] tmp = Locale.getAvailableLocales();
localeList = new Locale[5];
for (int i=0;i< localeList.length;i++){
localeList[i] = tmp[i];
}

return localeList;
}

public void setLocaleList(Locale[] localeList) {
this.localeList = localeList;
}

public HtmlDataTable getDt1() {
return dt1;
}

public void setDt1(HtmlDataTable dt1) {
this.dt1 = dt1;
}

public ClientIdExample() {
}
}

And generated HTML should look like:

    <table rules="all" frame="hsides" summary="This is a JSF code to create dataTable." dir="LTR" id="form1-dt1">
<thead>
<tr><th scope="colgroup" colspan="2">This is 'dataTable' demo</th></tr>
<tr>
<th scope="col">name</th>
<th scope="col">click</th>
</tr>
</thead>
<tfoot>
<tr><td colspan="2">The End</td></tr>
</tfoot>
<tbody>
<tr class="">
<td>
form1-dt1-0
<span style="margin: 5px; padding: 5px;">japoński (Japonia)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-0-editRow" id="form1-dt1-0-editRow"></td>
</tr>
<tr class="">
<td>
form1-dt1-1
<span style="margin: 5px; padding: 5px;">hiszpański (Peru)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-1-editRow" id="form1-dt1-1-editRow"></td>
</tr>
<tr class="">
<td>
form1-dt1-2
<span style="margin: 5px; padding: 5px;">angielski</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-2-editRow" id="form1-dt1-2-editRow"></td>
</tr>
<tr class="">
<td>
form1-dt1-3
<span style="margin: 5px; padding: 5px;">japoński (Japonia,JP)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-3-editRow" id="form1-dt1-3-editRow"></td>
</tr>
<tr>
<td>
form1-dt1-4
<span style="margin: 5px; padding: 5px;">hiszpański (Panama)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-4-editRow" id="form1-dt1-4-editRow"></td>
</tr>
</tbody>
</table>

 Now I will present 3 ways to highlight entire row with click event. Those functions are simple so they don't need an explanation.

1)
function toggleRow(clientId)
{
$('#'+clientId).closest('tr').toggleClass("selectedRow");
}
2)
$(document).ready(function(){
$('input[id$=editRow]').click(function(){
$(this).closest('tr').toggleClass("selectedRow");
return false;
});
});
3)
$(document).ready(function(){
$('#${clientIdExample.dt1.clientId} tr td > input').click(function(){
$(this).closest('tr').toggleClass("selectedRow");
return false;
});
});

 Working with jQuery and JSF 2.0(javax.faces.SEPARATOR_CHAR)

Generally when you use the JSF framework and look inside the HTML output you will find that clientId is separated by a colon sign ":". Unfortunately this sign is not allowed when you use the jQuery library because it is reserved for jQuery selectors. JavaServer Faces 2.0 comes with a parameter: javax.faces.SEPARATOR_CHAR. In this case you should change default separator to another one which is accepted by jQuery. For example (web.xml):

    <context-param>
<param-name>javax.faces.SEPARATOR_CHAR</param-name>
<param-value>-</param-value>
</context-param>

Call Ajax across Facelets Template and Clients 

In this example I will show how to call Ajax to update UIComponent in Template.xhtml from AjaxEngine.xhtml(Facelets Client). We will use the Javascript function jsf.ajax.request instead of f:ajax and we will use the clientId property of UIControl. 

If we want to use Javascript jsf.ajax.request in pure form we need to load appropriate client script

<h:outputScript name="jsf.js" library="javax.faces" target="head" />

This will generate something like this:

<script src="/PrimeFacesLearning/javax.faces.resource/jsf.js.jsf?ln=javax.faces&amp;stage=Development" type="text/javascript"></script>

Template.xhtml: 

<h:body>
<f:view contentType="text/html" locale="pl_PL">
<h:form id="form1" prependId="true" binding="#{template.form1}">
<ui:debug id="debug1" rendered="true" hotkey="l">
</ui:debug>
<div id="container">
<div id="header"></div>
<div id="center-column">
<div id="left-column">
<h:outputText id="ajaxText" binding="#{template.ajaxText}" value="${ajaxEngine.firstname}" />
</div>
<br />
<p:panel id="right-column" styleClass="right-column" toggleable="true" closable="true">
<ui:insert name="right-column" >
</ui:insert>
</p:panel>
</div>
</div>
</h:form>
</f:view>
</h:body>

 DummyAjax.xhtml

<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./resources/layout/Template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:sc="http://java.sun.com/jsf/composite/Controls">

<ui:define name="right-column">
<h1> f:ajax example using Facelets Templating</h1>
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<script src="/PrimeFacesLearning/javax.faces.resource/jsf.js.jsf?ln=javax.faces&amp;stage=Development" type="text/javascript"></script>
<h:panelGrid id="panelGrid1">
<h:inputText value="#{ajaxEngine.firstname}" onkeyup="jsf.ajax.request(this, event,{render:'form1-text ${template.ajaxText.clientId} form1-count'}); return false">
</h:inputText>
<h:outputText id="text" value="#{ajaxEngine.firstname}" escape="false"/>
<br />
Firstname char count: <h:outputText id="count" value="#{ajaxEngine.count}" />
</h:panelGrid>
</ui:define>
</ui:composition>
    /**
* This code will be automatically called when jsf.ajax.request will
* be populated from client side.
* Here we also set another property of DummyAjax - Integer count
* to manipulate other variables in managed bean.
* @param firstname
*/
public void setFirstname(String firstname) {
this.firstname = firstname;
setCount(getFirstname().length());
}

In the code above we have two pages. Template.xhml and DummyAjax.xhtml as facelets template client. In template we have <h:outputText id="ajaxText" binding="#{template.ajaxText}" value="${ajaxEngine.firstname}" /> and in DummyAjax.xhtml we have

 <h:inputText id="input1" value="#{ajaxEngine.firstname}" />  
<h:outputText id="text" value="#{ajaxEngine.firstname}" escape="false"/>

All those three controls refers to one managed bean property: #{ajaxEngine.firstname}. The next interesting thing is calling Ajax on each keyup.

onkeyup="jsf.ajax.request(this, event,{render:'form1-text 
${template.ajaxText.clientId} form1-count'}); return false"

Method expression for getting clientId of each UIComponent:
form1-text #{template.form1.findComponent("panelGrid1").findComponent("text").clientId}
form1-input1 #{template.form1.findComponent("panelGrid1").findComponent("input1").clientId}
form1-count #{template.form1.findComponent("panelGrid1").findComponent("form1-count").clientId}

And in the end last thing is really usefull which is body of method setFirstName(String firstname) where we have a chance to update as many properties as we want.

JavaServer Faces 2.0 Control Composition

I wouldn't dwell on ${cc.attr.id} just because this works just the same as all content in article.
Short example:

<?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:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:cc="http://java.sun.com/jsf/composite">

<!-- NO INTERFACE -->
<cc:interface>
</cc:interface>

<!-- IMPLEMENTATION -->
<cc:implementation>
${cc.attrs.id},${cc.clientId} <br />
</cc:implementation>
</html>

<h:form id="form1" prependId="true">
<sc:Dummy id="dummy1" /><br />
<sc:Dummy id="dummy2" />
</hform>

<!--browser output-->
dummy1, form1-dummy1 <br />
dummy2,form1-dummy2

Article Summary

This article should give you understanding of how to get clientId with diffrent scenarios. You should also know how to use JSF 2.0 with jQuery and you have learned how to call Ajax without the f:ajax tag. You can download the source code from table below.

 Useful links

Expression Language Official reference to Java 6 EL.
Composite Components example. Simple but usefull example of how to use CC.
jsf.ajax.* javadoc Full reference to jsf.js library.
jsf ajax example Example with f:actionListener and jsf.ajax.request(...)
FireBug This is one of the best tools for browsing client html, debugging Javascript and watching real Ajax requests.
PrimeFaces My favourite jsf tag library. Uses jQuery as it's Javascript engine. Many great controls and of course open source.
First, second gool article Those article show details about JSF clientId properties.
jQuery This library simplifies a developers life.
Subversion repository of code. Simple NetBeans project where I learn JSF 2.0
Published at DZone with permission of its author, Robert Piesnikowski.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Oleg Varaksin replied on Wed, 2011/02/23 - 9:14am

Hello Robert,

 Instead of

$('#'+clientId).parent().parent().toggleClass("selectedRow");

you could better use

$('#'+clientId).closest('tr').toggleClass("selectedRow");

I think, it's more undependent from the structure of table content.

 

 

Robert Piesnikowski replied on Wed, 2011/02/23 - 12:25pm

Yes you've got right. Thanks for hint and cheers! I've modified as you mentioned.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.