Latest Entries »

Monday, February 21, 2011

JavaServer Faces 2.0 ClientId with jQuery

Introduction

In this article I will show how to work with clientId property of UIComponent, which has been improved in JavaServer Faces 2.0 about finding concrete id from client side and how 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  as JSF 2.0 implementation and GlassFish 3.0.1.

Hello ClientId

 In this step we will create first simple web application with only one page.
 1.From 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 very various cases. Two steps are needed to get clientId by binding. First we need to add binding attribute and connect this attribute with Managed Bean property corresponding to 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 dolar sign $ to access properties (form1 and component)of managed bean. In (4),(7),(6) we used hash sign # to refer UIComponent methods like findComponent to find child component and uses panel1 properties.

ClientId with NamingContainer

Now I will put some examples of my web application and explain how does it all work. Let start with h:dataTable with few rows and two columns. Second column will contain a h:commandButton and we want use this button to do some client javascript action.
 Here is 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 I don't put explaination.

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

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


Generally when you use jsf framework and look inside html output you can find that clientId is separated by colon sign ":". Unfortunatelly this sign is not allowed when you use jQuery library because is reserved for jQuery selectors. JavaServer Faces 2.0 comes with parameter: javax.faces.SEPARATOR_CHARIn 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 javascript
jsf.ajax.request function instead of f:ajax and we will use 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 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}. 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


In the almost of the end of article I would'n 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 scenarious. You should also know how to use jsf 2.0 with jQuery and you have learned how to call ajax without f:ajax tag. You can download 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 referene to jsf.js library.
jsf ajax example Example with f:actionListener and jsf.ajax.request(...)
FireBug Oh God. This is one of the best tool for browse client html,
debug javascript and watch real ajax requests.
PrimeFaces My favourite jsf tag library. Uses jQuery as 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 simplify developer life.
Subversion repository of code.Simple NetBeans project where I learn JSF 2.0