Skip to main content

Ajax tag events and listeners

Posted by driscoll on September 26, 2009 at 1:08 PM PDT

Today we're going to talk about two features of JSF 2.0's f:ajax tag: the event attribute and the listener attribute.

The use of both of these is really, really simple - so I'll just briefly cover the basics, and then launch directly into the sample code.

The "event" attribute of the ajax tag indicates which event to use to trigger the ajax request. There are any number of possible events allowed: You can use the standard browser DOM events (like click, change, keyup, etc. You can also use two special event values - action and valueChange. These two special values correspond to the same events that happen on the server side in JSF. On the client side, action is typically mapped to click, while valueChange is mapped to change or click, depending on the component.

The "listener" attribute of an ajax tag is a method that is called on the server side every time the ajax function happens on the client side. For instance, you could use this attribute to specify a server side function to call every time the user pressed a key - Handy, eh?

Anyhow, without further ado, let's see how this works in a page. We're going to detect every time the user lifts a key (the keyup event) - when that happens, we'll run an ajax command which updates a counter, and refreshes an output field.

Here's the using page:

   1 <?xml version='1.0' encoding='UTF-8' ?> 
   2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   3 <html xmlns="http://www.w3.org/1999/xhtml"
   4       xmlns:h="http://java.sun.com/jsf/html"
   5       xmlns:f="http://java.sun.com/jsf/core">
   6
   7     <h:head><title>Ajax Tag Event and Listener Demo</title></h:head>
   8     <h:body>
   9         <h:form id="form">
  10             <br/>
  11             Echo test: <h:outputText id="out" value="#{listenBean.hello}"/>
  12             <br/>
  13             String Length: <h:outputText id="count" value="#{listenBean.length}"/>
  14             <br/>
  15             <h:inputText id="in" value="#{listenBean.hello}" autocomplete="off">
  16                 <f:ajax event="keyup" render="out count eventcount" listener="#{listenBean.update}"/>
  17             </h:inputText>
  18             <br/>
  19             Event count: <h:outputText id="eventcount" value="#{listenBean.eventCount}"/>
  20         </h:form>
  21
  22     </h:body>
  23 </html>

As I said, we tag the inputText (line 15) with an ajax tag (line 16). That ajax tag listens for the keyup event - when such an event occurs, we send an ajax request to the server. That ajax request will run a listener method (listenBean.update), apply the new string value from the inputText (listenBean.hello), and then render out (line 11), count (line 13), and eventcount (line 19).

The bean itself is nothing special: here's the example below:

   1 import javax.faces.bean.ManagedBean;
   2 import javax.faces.bean.ViewScoped;
   3 import javax.faces.event.AjaxBehaviorEvent;
   4
   5 @ManagedBean(name="listenBean")
   6 @ViewScoped
   7 public class ListenBean {
   8
   9     private String hello = "Hello";
  10
  11     private int length = hello.length();
  12
  13     private int eventCount = 0;
  14
  15     public String getHello() {
  16         return hello;
  17     }
  18
  19     public void setHello(String hello) {
  20         this.hello = hello;
  21     }
  22
  23     public int getLength() {
  24         return length;
  25     }
  26
  27     public int getEventCount() {
  28         return eventCount;
  29     }
  30
  31     public void update(AjaxBehaviorEvent event) {
  32         length = hello.length();
  33         eventCount++;
  34     }
  35 }

So - questions? Ask below.

Comments

thanks

thanks

Hello, This a good example

Hello,
This a good example for AJAX event. This could be out of scope of this article - Ajax updates the count on the client browser as it entered on the textfield. But it does not update the "page source code". In other words new/updated part of the component tree content is not updated in the "page source code". Is there any solution.

How to call custom Javascript function?

Ok, listener is very fine, I can call function on my bean. But I have some JavaScript function on my page, which I want to be executed when updated view is rendered. How can I do this? I know I can put <script>function(param);</script> in part I am rerendering, but isn't there any better solution?

Better how?

 Actually, that way is perfectly fine.  So my question would be: better how?

 

That said, you can do the same thing with events:

http://weblogs.java.net/blog/driscoll/archive/2009/09/26/ajax-tag-events...

Missing Delay Feature

Hi Jim,

I love the JSF 2.0 posts, and this one is no exception, but I think one important missing feature from the new JSF 2.0 Ajax stuff is a mechanism to provide a delay in the request and to throw away the old request if a more recent version comes before the delay is over to prevent too many requests hitting the server. In your example, an ajax request is posted for each key press while it should only send a request after a burst of typed characters when the user stops typing for half a second or so.

Granted, this can easily be added by third parties, but considering it should be used in nearly half the ajax requests sent and a zero delay could be used for immediate requests, I think it is commonly used enough that it could have been a part of the spec. Since this type of delay is required in real world apps and used in half the requests, as soon as you start using JSF 2.0 for practical purposes the first thing you need to do is start wrapping the JSF ajax request call in your own code to handle the delay or start looking for third party code to do it (of which there isn't any since the JSF component vendors aren't ready for 2.0 yet).

Cheers,

Andy Gibson

You mean RichFaces Queues

RichFaces queues handle this of course, but writing your own really is trivial - about 10 lines of code. And it really isn't useful for "about half" of Ajax calls, I'd argue - rather, it's mostly needed for keypress events. We're anticipating that keypress events are the exception, rather than the rule, and that's certainly true for most Ajaxified web pages that I visit.

Given that it's so easy to do yourself, and given that it's so easy for us to get wrong, by specifying it badly, we opted to wait to include it in the next version. RichFaces will be adding this in their next release, which should be out pretty soon.

This isn't to minimize the need - but we do need to be careful in specifying things, since once specified, this feature will remain until the heat-death of the universe - we simply don't make backward incompatible changes in the Java world, so we end up living with our mistakes for a long, long time.

I'll blog about doing this yourself sometime soon.

Is it soon now?

Alright, now that java.net is back in operation I'll try this again. I may be thick, but I can't figure out where to put the 10 magical lines of code that will give me the delay feature, nor what those lines are. Any help would be greatly appreciated. Joel

Posted two months before

 Actually, I answered this request in October, look here: 

http://weblogs.java.net/blog/driscoll/archive/2009/10/19/request-aggrega...

My 'about half' estimate is

My 'about half' estimate is coming from the idea that a single search form may have multiple auto-complete entries plus the ability to perform continuous search result fetches as you type whereas there may be only one actual search/select/delete. Simple Crud may have numerous auto-completes on an entry form plus ajax validation and possibly and ajaxified save button at the end. It may be because I develop more web applications than web sites, but I find keyboard driven ajax far more common. Regardless, I understand the need to limit the content of the spec to clearly defined core features.

I'm no Javascript genius but took a look at writing my own which works fairly well except for the fact that the ajax tag has a listener attached whereas the direct javascript method has no way of specifying a function to call on the server.

The RichFaces guys are supposed to be releasing a 4.0 Alpha at the end of October so we can wait and see what that brings,

Cheers,

Andy Gibson

That would be the root difference in our estimate

I don't, generally, use products which are "page as application" ajax apps. So that is certainly the difference in our perspective.

As for calling a method as part of the ajax request, you can obtain the much the same functionality by specifying an action listener, if it's an action component, or, since we are talking about character driven events, you can then specify a valueChange listener. Not quite the same as an ajaxListener, but it's likely that it'll give you what you need.

But here's an honest question for you: If you really using this strictly for autocomplete, isn't an autocomplete component what you need, rather than a more complex request aggregation function? Can you think of another reason to have aggregation besides autocomplete, that won't be really difficult to use well?

The reason I ask is that it's generally considered bad practice to add a feature to an API to support a single use case. It may be that specifying an autocomplete input component may make more sense than a generally reusable request aggregation function. If all you use it for is autocomplete....

In the broad scheme of things you are correct,

While I think a request delay extends beyond a single use case, auto completion does not. In the broad scheme of things you are correct, this kind of feature should be handled within a component as opposed to being written from scratch in each page. Delayed requests should be implemented as part of a common base component / library (I think it is in Richfaces/A4jsf) because of the different types of components that could use it. The documentation for richfaces lists this as a base property and shows it is included in a number of components beyond auto completion. Regardless , ideally, the auto completion should be a stand alone component based on some core library that provides delayed requests.

However, for this, and other reasons, your average JSF developer isn't going to write their own component framework from scratch, they will obtain one from third party component writers who have put the time and thought into doing it properly (Which I guess kind of makes this discussion moot :).

Oh, as for value change listener, it worked a treat, thanks for that.

Cheers,

Andy Gibson