C H A P T E R  12

Rich Components JavaScript API, Client Functions, and Using jQuery

In this chapter we are going to cover a number of miscellaneous but important components and functions. We will start with the widely used #{rich:component()} client function and <rich:componentControl> behavior. Both make it possible to call the JavaScript API available on a component. We will then cover other client functions. We will finally cover two remaining components: <rich:jQuery>, which integrates the jQuery JavaScript framework into a JSF application, and <rich:hashParam>, which allows passing a group of client-side parameters to a client-side component.

Invoking a Component’s JavaScript API

In this section, we are going to show you two different ways to invoke the component’s JavaScript API.

Using #rich:component(id) Function

We already covered #{rich:component()} in Chapter 4 when we introduced rich components. But let’s cover it here briefly again. As you know by now, many RichFaces components provide JavaScript API. When a component provides JavaScript API, it’s possible to control the component on the client, such as switching tabs in case of a tab component, or showing and hiding in the case of a popup component. Before we can invoke a JavaScript function on a component, we need to get a reference to that component on the client, and that’s exactly what #{rich:component()} does. When placed on a page, it renders a JavaScript that obtains a reference to the component in the browser.

Let’s see how it works in an example. We will start with one of the most popular components in RichFaces: <rich:popupPanel>. This popup is usually rendered on the page, but it is hidden from view. Showing and hiding a popup is done on the client-side (e.g., the browser). Listing 12-1 shows a popup panel.

Listing 12-1. A popup panel

<h:outputLink value="#"  
   onclick="#{rich:component('popup')}.show();return
      false;">Open</h:outputLink>
   <rich:popupPanel header="RichFaces" id="popup">
      <h:panelGrid>
         <h:outputText value="This is a RichFaces popup" />
         <h:outputLink value="#"
            onclick="#{rich:component('popup')}.hide();">Close</h:outputLink>
      </h:panelGrid>
</rich:popupPanel>

The most important code is in the onclick event in both open and close links. As we already mentioned, showing and hiding a panel is done on the client, so we need to get a reference to the popup component on the client and invoke JavaScript API. That’s exactly what we do with #{rich:component()}. #{rich:component()} gives a reference to all the component JavaScript API. With this reference, we can invoke any available function. In our example, we call show() to show the component, and hide() to hide the component. How do you know what API is available? RichFaces documentation lists all functions for each component. Whenever you need to get a reference to the component’s JavaScript API, you use #{rich:component()}, passing it the component id, as follows:

#{rich:component(id)}

It’s important to point out that the function takes the component id, not the client id.

images Tip RichFaces documentation at www.jboss.org/richfaces lists all JavaScript API for each component.

So far we used show() without any arguments. If we want to pass any arguments to the popup panel, we have to use this signature: show(event, {param1:value, param2:value}). Listing 12-2 shows the updated popup example.

Listing 12-2. Passing arguments to the popup panel

<h:outputLink value="#" onclick="#{rich:component('popup')}.show(event,
   {top:5,left:5,width:200,height:250});">Open</h:outputLink>

<rich:popupPanel header="RichFaces" id="popup">
   <h:panelGrid>
      <h:outputText value="This is a RichFaces pop-up" />
      <h:outputLink value="#"
         onclick="#{rich:component('popup')}.hide();">Close</h:outputLink>
   </h:panelGrid>
</rich:popupPanel>

event is a variable and the parameters are passed in JSON format.

images Tip Any component JavaScript function that takes arguments should either be invoked with no arguments (if supports calls with just default values) or should pass all the arguments with event being the first: foo(event, options).

Let’s try another example using the accordion component. When using an accordion, to switch to a different item we just click that item. Another way to switch items is to use the JavaScript API that the component provides. Figure 12-1 shows the accordion followed by the code listing.

images

Figure 12-1. RichFaces accordion panel with three major U.S. cities

Listing 12-3 shows the page code.

Listing 12-3. The page code

<h:form>
   <rich:panel style="width:350px">
      <rich:accordion id="cities">
         <rich:accordionItem header="New York City" name="nyc">
            <h:outputText value="You selected New York City" />
         </rich:accordionItem>
         <rich:accordionItem header="San Francisco" name="sf">
            <h:outputText value="You selected San Francisco" />
         </rich:accordionItem>
         <rich:accordionItem header="Los Angeles" name="la">
            <h:outputText value="You selected Los Angeles" />
         </rich:accordionItem>
      </rich:accordion>
   </rich:panel>
</h:form>

Accordion provides JavaScript API for switching items. We are going to add a button for each city and when the button is clicked, the item corresponding to a city will be selected. Listing 12-4 shows the three buttons.

Listing 12-4. Shows the three buttons

<h:form>
   <rich:panel style="width:350px">
      <rich:accordion id="cities">
         <rich:accordionItem header="New York City" name="nyc">
            <h:outputText value="You selected New York City" />
         </rich:accordionItem>
         <rich:accordionItem header="San Francisco" name="sf">
            <h:outputText value="You selected San Francisco" />
         </rich:accordionItem>
         <rich:accordionItem header="Los Angeles" name="la">
            <h:outputText value="You selected Los Angeles" />
         </rich:accordionItem>
      </rich:accordion>

      <input type="button" value="New York City"
         onclick="#{rich:component('cities')}.switchToItem('nyc')" />
      <input type="button" value="San Francisco"
         onclick="#{rich:component('cities')}.switchToItem('sf')" />
      <input type="button" value="Los Angeles"
         onclick="#{rich:component('cities')}.switchToItem('la')" />
   </rich:panel>
</h:form>

We again use the #{rich:component()} client function to get a reference to the accordion component first (cities id). Once we have a reference, we can invoke any available JavaScript function on the component. In our example, we call switchToItem(), passing it the name of the accordion item to which we want to switch.

In Listing 12-4, the buttons were placed inside the form. That’s not required and the buttons could have been placed outside the form. Usually, when invoking a JavaScript function, the form is not required because we are not making any requests to the server. However it’s possible that the component itself will send an Ajax request according to the API called. The default switch type for an accordion is ajax. This means that when a button is clicked it calls the API method on <rich:accordion> to switch the item, and an Ajax request is sent by the <rich:accordion> to the server. An easy way to check this is to place an <a4j:log> component on the page. Whenever an Ajax request is sent, this component will output request/response information. If we change accordion’s switchType="client", then no request will be sent because all the items are rendered on first page load and further switching is done entirely on the client.

In addition to switching to a named item like we did in our example, Listing 12-4, accordion also supports switching to first, last, next, and previous items. Listing 12-5 shows these four buttons.

Listing 12-5. Shows the first, last, next, and previous items buttons

<input type="button" value="First"
   onclick="#{rich:component('cities')}.switchToItem('@first')" />
<input type="button" value="Next"
   onclick="#{rich:component('cities')}.switchToItem('@next')" />
<input type="button" value="Previous"
   onclick="#{rich:component('cities')}.switchToItem('@prev')" />
<input type="button" value="Last"
   onclick="#{rich:component('cities')}.switchToItem('@last')" />

The accordion provides predefined names for switching to these tabs, such as @first, and this naming format closely follows JSF 2 convention.

images Tip Other RichFaces components that can be switched and are built out of “items” such as <rich:accordionItem>, which provide the same switchToItem() API and the same predefined names.

Using <rich:componentControl>

In the previous section we showed you how to invoke component’s JavaScript API using the #{rich:component()} function. There is another way to invoke the API. This second approach is more declarative and uses <rich:componentControl> behavior. The name of the component implies what it does. It makes it possible to control a component from another component that is done via JavaScript.

Let’s take two examples from previous sections and update them to use <rich:componentControl>. Listing 12-6 shows the popup panel example updated using <rich:componentControl> instead of the #{rich:component()} function.

Listing 12-6. Shows the popup panel example updated using <rich:componentControl> instead of the #{rich:component()} function

<h:outputLink value="#">
   <h:outputText value="Open" />
   <rich:componentControl event="click" target="popup" operation="show" />
</h:outputLink>

<rich:popupPanel header="RichFaces" id="popup">
   <h:panelGrid>
      <h:outputText value="This is a RichFaces pop-up" />
      <h:outputLink value="#">
      <h:outputText value="Close" />
         <rich:componentControl event="click" target="popup"
            operation="hide" />
      </h:outputLink>
   </h:panelGrid>
</rich:popupPanel>

Let’s take a closer look at the opening link. Instead of using #{rich:component()} we nest <rich:componentControl> behavior inside. <rich:componentControl> attaches itself to the parent component and then invokes a JavaScript function on another component. We specified the following three attributes: event="click" indicates which event to listen on the parent component; target="popup" indicates on which component to invoke the function; operation="show" indicates which function to invoke on the component. This looks very similar to using #{rich:component()}, simply done in a more declarative fashion. To close (hide) the popup, we use the same setup, but instead of invoking the show operation (show() function), we invoke the hide operation (hide() function). One major difference between these two approaches is that the #{rich:component()} function can be used with any HTML tag, but being a behavior, <rich:componentControl> can be attached only to another JSF component.

images Tip When specifying operation in <rich:componentControl>, only the operation (function) name is used, without parenthesis ().

Passing Parameters with <a4j:param>

Now let’s update the accordion example to use <rich:componentControl>. We are not going to repost the accordion markup because it stays the same. We will only update the buttons. When we switched accordion items, we passed the item’s name to the switchToItem() function. Let’s see how we can do the same using <rich:componentControl>. Listing 12-7 shows using <rich:componentControl> on external buttons to control the items.

Listing 12-7. Using <rich:componentControl> on external buttons to control the items

<h:commandButton value="New York">
   <rich:componentControl event="click" target="cities"
      operation="switchToItem">
      <a4j:param value="nyc" />
   </rich:componentControl>
</h:commandButton>
<h:commandButton value="San Francisco">
   <rich:componentControl event="click" target="cities"
      operation="switchToItem">
      <a4j:param value="sf" />
   </rich:componentControl>
</h:commandButton>
<h:commandButton value="Los Angeles">
   <rich:componentControl event="click" target="cities"
      operation="switchToItem">
      <a4j:param value="la" />
   </rich:componentControl>
</h:commandButton>

Notice that for the operation attribute, we specify only the function name; there is no option to pass parameters there. How do we pass the parameter? We include <a4j:param> with the accordion item’s name inside <rich:componentControl>. It’s possible to pass multiple parameters; they will be applied in the order the <a4j:param> tag is listed.

Instead of <a4j:param>, we can also use the standard <f:param> tag. Both will give us the same result. Listing 12-8 shows using <f:param> with a button.

Listing 12-8. Using <f:param> with a button

<h:commandButton value="New York">
   <rich:componentControl event="click" target="cities"
      operation="switchToItem">
      <f:param value="nyc" />
   </rich:componentControl>
</h:commandButton>

However, <a4j:param> adds one very important feature. In addition to passing parameters evaluated from server-side expressions to client functions, the <a4j:param> value can also be evaluated as a client-side JavaScript expression when the noEscape attribute is set to true. We show an example of this in next section.

Passing JavaScript Hash with <rich:hashParam>

In previous sections we saw how to pass string-based parameters. However, it’s also possible to pass a JavaScript hash to a function. RichFaces now comes with a new component called <rich:hashParam>, which allows you to pass a JavaScript hash or hash table to a JavaScript function. A hash table is very similar to a hash map; it consists of keys and associated values.

Let’s look at an example in Listing 12-9, which shows opening a popup panel and passing information such as width, height, and positioning via the <rich:hashParam> tag.

Listing 12-9. Opening a popup panel and passing information via the <rich:hashParam> tag

<h:outputLink value="#">
   <h:outputText value="Open" />
   <rich:componentControl event="click" target="popup" operation="show">
      <a4j:param noEscape="true" value="event" />
      <rich:hashParam>
         <a4j:param name="width" value="500" />
         <a4j:param name="height" value="300" />
         <a4j:param name="minWidth" value="300" />
         <a4j:param name="minHeight" value="150" />
         <a4j:param noEscape="true" name="left"
            value="(jQuery(window).width()/2)-250" />
         <a4j:param noEscape="true" name="top"
            value="(jQuery(window).height()/2)-150" />
      </rich:hashParam>
   </rich:componentControl>
</h:outputLink>

<rich:popupPanel header="RichFaces" id="popup">
   <h:panelGrid>
      <h:outputText value="This is a RichFaces pop-up" />
      <h:outputLink value="#">
         <h:outputText value="Close" />
         <rich:componentControl event="click" target="popup"
            operation="hide"/>
      </h:outputLink>
   </h:panelGrid>
</rich:popupPanel>

From Listing 12-9, all parameters passed to the popup are inserted into a JavaScript hash tab with the <rich:hashParam> tag. The actual parameter is defined with the <a4j:param> tag but you can also use the standard <f:param> for all except top, left, and event parameters. For top and left, the value is not a string-based value but a jQuery function that calculates the positioning based on the current browser window size. Setting noEscape="true" is required in those cases; otherwise, the parameters will be treated as server-side expressions and the jQuery function will not be invoked.

images Note As of writing of this book, only <rich:popupPanel> component accepts a JavaScript hash table as an argument to its API. We anticipate more components will support JavaScript hash table arguments in the future.

images Note You might be wondering why we pass <a4j:param noEscape="true" value="event"> as the first parameter. This is required because the show method has the following signature : show(event, options). You can invoke show() without any arguments, but if you do provide arguments, both must be specified.

Other RichFaces Client Functions

In addition to the widely used #{rich:component()} to invoke client JavaScript API, RichFaces provides the following client-side functions:

  • #{rich:clientId(id)}: Returns a client id for a component from passed component id
  • #{rich:element(id)}: Returns a DOM element from passed component id
  • #{rich:findComponent(id)}: Returns a server-side component instance for passed component id
  • #{rich:isUserInRole(role)}: Returns if the user has a specified role

Let’s try the first three in an example and then come back to the #{rich:userInRole()} function. To start, we are going to place a <rich:calendar> on the page, shown in Listing 12-10, and use this component with all the functions.

Listing 12-10. Placing a <rich:calendar> on the page

<h:form id="form">
   <rich:calendar popup="true" id="calendar" />
</h:form>

First, as these are client-side functions, they are invoked via EL, inside #{}. If we need to get the calendar’s client id, we place this on a page, as follows:

#{rich:clientId('calendar')}

And we get the following output:

form:calendar

We place them on a page because it’s an easy way to test and see what they produce. However, in real applications, you will most likely use them from inside a JavaScript function.

If we need to get a calendar’s DOM element, we place this on a page, as follows:

#{rich:element('calendar')}

And we get the following output:

document.getElementById('form:calendar')

Let’s also try #{rich:component} and see what we get. So, we place the following on a page:

#{rich:component('calendar')}

And we get the following result:

RichFaces.$('form:calendar')

Behind the scenes this is a jQuery selector that will let us call the available JavaScript functions on this component. We don’t recommend using JavaScript from #{rich:component(id)} directly anywhere. #{rich:component(id)} is a shortcut and in case of changes to implementation or refactoring, you won’t have to make any changes to the application.

Let’s now try #{rich:findComponent}, which is best demonstrated in an example shown in Listing 12-11.

Listing 12-11. Using #{rich:findComponent}

<h:form id="form">
   <h:panelGrid>
      <h:outputText value="Text:" />
      <h:inputText id="input">
         <a4j:ajax event="keyup" render="echo"/>
      </h:inputText>
      <h:outputText value="Echo:" />
      <h:outputText id="echo" value="#{rich:findComponent('input').value}" />
   </h:panelGrid>
</h:form>

This example shows a somewhat typical echo-like example. Any input typed is echoed immediately on the next line because we use the keyup event. What’s interesting is that there is no managed bean or managed property bound and used in this example. The page in our example is submitted as always and the value entered is set into the component. As we don’t bind the input component to a managed bean property, the value just stays in the component. Using #{rich:findComponent(id)}, we find that input component in a JSF component tree, get its value, and then display it on the page with #{rich:findComponent(id).value}. In other words, we are working directly with a JSF component tree, without needing a backing bean. This could be useful if you need to test something quickly without having to build and bind to a model.

The last function is called #{rich:isUserInRole(role)}. It provides a shortcut to a standard Java EE security feature, which in turn makes the following call:

facesContext.getExternalContext.getUserInRole(role)

What’s good about this function is that it doesn’t care how and where roles are defined. Roles can be defined in web.xml but can also be defined somewhere else, depending on application configuration. The function returns true if current user is in the provided role. For example, suppose only the administrator should see some part of a page, as shown in Listing 12-12.

Listing 12-12. Example of the administrator’s defined role

<rich:panel header="Admin panel" rendered="#{rich:isUserInRole('admin')}">
  Very sensitive information
</rich:panel>

 <rich:panel header="User panel">
   General information
</rich:panel>

In the above example, unless the current user is authenticated as admin, the top panel will not be rendered. For this to work, appropriate security roles need to be defined in the web.xml file.

Using jQuery with <rich:jQuery>

jQuery JavaScript framework is at the heart of RichFaces because it’s the only JavaScript framework used (and extended) by RichFaces. The following is a jQuery description from jQuery.com: “jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development.”1

We also would like to add that jQuery is one of the most popular JavaScript frameworks out there. We highly recommend that you do some reading about how jQuery works. A good starting point is the JQuery: The Write Less, Do More, JavaScript Library web site at http://jquery.com. You can also find a number of good books out there. One of them is jQuery: Novice to Ninja by Earle Castledine and Craig Sharkie (SitePoint, 2010).

jQuery works with the browser DOM. With jQuery, you first select a single element or group of elements in the DOM and then do something with it or query it. If this particular query should be done when a button is clicked, for example, then we also attach this selector/query to some HTML element. There are many different tools, easy and advanced, to select an element, and many different things you can “perform” on the selection. Why do we need the <rich:jQuery> tag? <rich:jQuery> allows a more convenient and declarative way of adding jQuery queries to a page and its elements. One last thing to mention, jQuery being a JavaScript framework, it works in the client or the browser. Let’s do an easy example with <rich:panel> shown in Listing 12-13.

Listing 12-13. Example with <rich:panel>

<rich:panel header="New York" id="nycInfo" style="width:50%">
   New York is the most populous city in the United States and the center of the New York
   Metropolitan Area, one of the most populous metropolitan areas in the world. New York
   exerts a significant impact upon global commerce, finance, media, culture, art, fashion,   
   research, technology, education, and entertainment. As the home of the United Nations
   Headquarters, it is also an important center for international affairs. The city is often
   referred to as New York City or the City of New York to distinguish it from the state of New
   York, of which it is a part. Source: http://en.wikipedia.org/wiki/New_York_City.
</rich:panel>

Let’s say we would like to change the header title from “New York” to “New York City.” This is easily done with jQuery. We first attach jQuery to a button, on button click we select the panel, and then we do the content change. Listing 12-14 shows a button that does that.

Listing 12-14. Attaching jQuery to a button

<input type="button" id="changeButton" value="Update panel" />
<rich:jQuery selector="#changeButton"
   query="click(function(){
      $('#nycInfo .rf-p-hdr').text('New York City'),
})"/>

The selector attribute is used to select one or more elements on the page. In our example, selector="#changeButton" selects the button that will be clicked. query binds the handler function to the click event on the selected button. Inside the handler function, we first select the panel (#nycInfo), then we select its header by its CSS class (.rf-p-hdr) and invoke the text() function to modify the header. You might be wondering why we first select #nycInfo and then .rf-p-hdr. A rich panel is a complex component and consists of a number of HTML tags. jQuery allows you to filter elements, and only returns the elements that you need. #nycInfo would return the entire panel—and that’s not what we need. However, once we have the panel and search for .rf-p-hdr, we get the header element which we want to modify.

____________________

images Note $('id') is a shortcut for jQuery('id').

Let’s also change the text color inside the panel to blue. Listing 12-15 shows the changes.

Listing 12-15. Change the text color inside the panel

<input type="button" id="changeButton" value="Update panel" />

<rich:jQuery selector="#changeButton"  
   query="click(function(){
      $('#nycInfo .rf-p-hdr').text('New York City'),
      $('.rf-p-b').css('color', 'blue'),
})"/>

Notice that we didn’t specify a panel id before; this means we are not selecting a particular panel, and if we had other panels on the page, they would also change body color. To test this, just add another <rich:panel> to the page, for example, as shown in Listing 12-16.

Listing 12-16. Testing which panels would change body color

<rich:panel>
   This panel will also turn blue.
</rich:panel>

If you look at the query attribute value in Listing 12-15, it looks rather long and somewhat complicated. We can simplify the markup by setting the event via the event attribute, as shown in Listing 12-17. That attribute allows us to bind the query defined in the corresponding attribute to a specified event without an additional definition in query itself.

Listing 12-17. Simplify the markup by setting the event via the event attribute

<input type="button" id="changeButton" value="Update panel" />
<rich:jQuery selector="#changeButton" event="click"
   query="$('#nycInfo .rf-p-hdr').text('New York City'),
                $('.rf-p-b').css('color', 'blue')," />

Let’s add one more jQuery effect: add a button that hides the panel. Listing 12-18 shows the page code.

Listing 12-18. Adding a button that hides the panel

<input type="button" id="hideButton" value="Hide panel"/>
<rich:jQuery selector="#hideButton" event="click" query="$
   ('#nycInfo').hide()"/>

We use a built-in jQuery hide() function to hide the panel. The only other difference, instead of specifying the event in query, we use a separate event attribute to set the click event, which makes the tag markup even simpler. We can’t leave this without adding a show button, as shown in Listing 12-19.

Listing 12-19. Using a built-in jQuery hide() function to hide the panel

<input type="button" id="showButton" value="Show panel"/>
<rich:jQuery selector="#showButton" event="click" query="$
   ('#nycInfo').show()"/>

While using event attributes to define the query as an event handler, you might want to define the binding type because jQuery allows different binding types for event handlers. The attachType attribute is used for that. bind type is the default type and means that the event handler will be bound to all elements returned by the selector and currently present on the page. live type works the same as bind and also means that the event handler defined in the query will be bound to all elements that will appear on the page later (for example, created using JavaScript or loaded via Ajax). And one type means the event handler is bound to all elements currently defined by the selector attribute. After the first invocation of the event, the handler of one type is unbound such that it no longer fires when the event occurs.

Everything we just did can be written directly with jQuery, without using the <rich:jQuery> tag. Listing 12-20 shows everything we just did, but directly with jQuery.

Listing 12-20. Example using jQuery

<script>
$('#changeButton').click(function(){
    $('#nycInfo .rf-p-hdr').text('New York City'),
    $('.rf-p-b').css('color', 'blue'),
});
$('#hideButton').click(function(){
        $('#nycInfo').hide();
});
$('#showButton').click(function(){
        $('#nycInfo').show();
});
</script>

What is the difference between using jQuery directly and <rich:jQuery>? The differences are very minor. One difference is that using <rich:jQuery> has a more declarative syntax. Also, when <rich:jQuery> is used, the actual jQuery script file is automatically rendered into the page. However, if jQuery is used directly, it’s necessary to load the JavaScript file manually. There are a number of ways to do that. You can use @ResourceDependency or use the standard <h:outputScript> tag to load the file.

images Caution You should be careful when loading external libraries using standard JSF 2 loading mechanisms. In case the library you loaded manually conflicts with RichFaces built-in libraries, application pages may not work as expected, if at all.

Another option is to place <rich:jQuery> on the page as follows:

<rich:jQuery rendered="true"/>

This will render the script file, but will not render anything for the component.

Finally, there is one more difference when <rich:jQuery> is used and we search for some id in the selector attribute, as follows:

selector="#changeButton"

We can specify a component id and RichFaces will resolve it to the client id. When we use jQuery directly, we always need to specify the client id. In cases when the component is nested, the client id might be long.

images Tip If you need to select an element with client id such as form:img, it could conflict with CSS selector syntax. A work-around using double backslashes can be used to escape the colon character such that the identifier is read correctly instead of being interpreted as CSS selector syntax. For example: selector="#form\:img".

So far we have shown you how to attach event handlers. This means something is activated and the jQuery query is invoked. It’s also possible to define an inline statement to be evaluated while a page is loading or when loaded. For example, let’s look at Listing 12-21, which shows a classic addition of the zebra style to a table using jQuery.

Listing 12-21. Shows a classic addition of the zebra style to a table using jQuery

<style>
   .even-row {
      background-color: #FCFFFE;
   }
   .odd-row {
      background-color: #ECF3FE;
   }
</style>

<rich:dataTable id="gamesTable" value="#{olympicGamesBean.games}"
   var="game">
   <rich:column>
      <f:facet name="header">
         <h:outputText value="City" />
      </f:facet>
      <h:outputText value="#{game.city}" />
   </rich:column>
   <rich:column>
      <f:facet name="header">
         <h:outputText value="Country" />
      </f:facet>
      <h:outputText value="#{game.country}" />
   </rich:column>
   <rich:column>
      <f:facet name="header">
         <h:outputText value="Year" />
      </f:facet>
      <h:outputText value="#{game.year}" />
   </rich:column>
</rich:dataTable>

<rich:jQuery selector="#gamesTable tr:odd" query="addClass('odd-row')" />
<rich:jQuery selector="#gamesTable tr:even" query="addClass('even-row')" />

After rendering, the table will look like Figure 12-2.

images

Figure 12-2. Table with zebra style added with <rich:jQuery>

In this example, once the page is rendered, <rich:jQuery> will be invoked; it will select the table based on its id and add a CSS class to odd rows and a different CSS class to even rows. In this example, the query will be triggered when the DOM has been loaded and ready. Timing can be changed via the timing attribute. domready is the default value (used in our example) and will trigger the query once the DOM is ready. On the other hand, the value of immediate will trigger the query immediately after the JavaScript code is rendered.

Another way to use <rich:jQuery> is a named query. If we give <rich:jQuery> a name by using a corresponding attribute, we can then invoke the query as a regular JavaScript function from any other component. This is called a named query. An example is shown in Listing 12-22.

Listing 12-22. An example of a named query

<h:graphicImage width="100" value="/images/venice.png"
   onmouseover="larger(this, {})" onmouseout="normal(this, {})" />

<rich:jQuery name="larger" query="animate({width:'241px'})" />
<rich:jQuery name="normal" query="animate({width:'100px'})"/>

When the mouse is over the image (onmouseover), we call the larger() function, which is the name of the function defined by the <rich:jQuery> tag. When the mouse moves outside the image (onmouseout), we call the normal() function, also defined by <rich:jQuery>. For the named query to work, the object on which the query will be invoked has to be passed and that’s why we pass this object as the first argument. The second argument allows you to pass parameters to the jQuery function in the query shown in Listing 12-23.

Listing 12-23. Passing parameters to the jQuery function in the query

<h:graphicImage width="100" value="/images/venice.png"
   onmouseover="larger(this, {imageWidth:'241'})" onmouseout="normal(this,
      {})" />

<rich:jQuery name="larger" query="animate({width:options.imageWidth})" />
<rich:jQuery name="normal" query="animate({width:'100px'})"/>

Parameters are passed in JSON syntax as a second parameter in the JavaScript call. The options namespace is then used in the <rich:jQuery> query to access the passed function parameters.

images Tip Named <rich:jQuery> will produce JavaScript evaluated only after the call to the function is made. It will not be invoked on page rendering.

Summary

Even though this is a miscellaneous chapter, we covered a number of very important RichFaces features. We first learned how to invoke JavaScript API on components, as well as various ways for passing parameters to these functions. We then covered other RichFaces client functions, such as #{rich:isUserInRole(role)}, which provides a super-easy way to check whether the current user is in a particular defined role. In the last part of this chapter we covered <rich:jQuery>, which allows you to bind to an element and invoke jQuery queries in a declarative approach.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.190.175