; last updated - 7 minutes read

I always used to skip over page 167 of the PrimeFaces 5 manual. That's too bad: it's an exciting page. It's a list of the events a <p:dataTable> can fire. That's no less than 19 interesting events.

Quick reminder: what are JSF events?

Chances are you already know the concept of JSF events from the <f:metadata> section of your JSF applications. A standard JSF event, preRenderView, is frequently used together with view parameters. Doing so, your parameterized JSF page can be stored as a bookmark in the browser, much in the same way Amazon allows you to simply copy the link of the book review you're currently reading and send it to your friends:

This code snippet (taken from the JSF pet store demo of Antonio Goncalves) allows you to call the page by the URL "my.domain.com/searchresult.jsf?keyword=cat". Before rendering the page, the parameter "cat" is passsed to the parameter catalogController.keyword. Immediately before the page is drawn, the preRenderView event is fired and caught by a JSF bean method (catalogController.doSearch()). The method populates the bean just in time before the page is rendered.

How PrimeFaces uses JSF events internally

Another - slightly more exotic - example is the PostAddToViewEvent. The upcoming PrimeFaces 5.1 uses this event to extract JSR 303 bean annotation constraints. When PostAddToViewEvent is fired, the JSF beans are already initialized, so it's a good point in time to gather information from the JSF beans and add them to the JSF components. In theory, you could also use the preRenderView event, but it's called less often, so the resulting algorithm is more efficient.

Note that this use case is slightly different from the first example. PrimeFaces catches the event internally. Adding a f:metadata tag to every JSF page is not an option. The alternative is to implement and register a SystemEventListener. Instead of showing you Thomas Andraschko's sophiscated PrimeFaces code, I'll show you an alternative approach to populate the JSF bean of the first example:

@ManagedBean public class CatalogController implements SystemEventListener { public CatalogController() { FacesContext context = FacesContext.getCurrentInstance(); UIViewRoot root = context.getViewRoot(); root.subscribeToViewEvent(PreRenderViewEvent.class, this); } public boolean isListenerForSource(Object source) { return source instanceof UIComponent; } public void processEvent(SystemEvent event) throws AbortProcessingException { // populate the JSF bean } }

If you want to listen to an event in every JSF page of your application, you can replace the registration code in the constructor of the bean by a couple of lines in your faces.config file:

de.beyondjava.CatalogController javax.faces.event.PreRenderViewEvent

By now you've got an idea how useful JSF events are. Let's have a look at the 19 data table events.

Which events are fired by the data table?

AJAX events - and the data table's events in particular - bring the idea of events to GUI widgets. Putting it in a nutshell, the data table fires an event each time the user starts an interaction. That's a well-known concept among Windows programmers (and desktop GUI programmers in general). Programs written in Visual Basic or Javascript follow the event-driven paradigm. That's a different programming style than the request-response-paradigm JSF used to follow prior to JSF 2.

JSF 2 changed things by introducing AJAX events. These events look like traditional user interface events, but there's an interesting twist: they can be caught both on the client side and on the server side. Every Javascript event fires a JSF AJAX event (see this StackOverflow article).

The data table (and many other PrimeFaces widgets) go a step further by introducing custom events.

The first group of data table events fires when the user actually does something that requires the table to be redrawn:

  • sort: fired after sorting the table, typically by a double click on a column header
  • filter: fired after setting or modifying a filter
  • page: fired after browsing to another page
  • colResize: fired after changing the width of a column
  • colReorder: fired after moving columns (like in Excel)
  • rowReorder: fired after moving a row

The second group of events deals with selecting things: rowSelect, rowUnselect, toggleSelect, rowSelectRadio, rowSelectCheckbox, rowUnselectCheckbox, rowDblselect (fired when a row is selected not by a regular click, but by a double click).

The remaining events deal with editing events and the context menu. For instance, the "contextMenu" event is fired when the context menu is opened.

How can you catch the events?

To catch an event, simply add a <p:ajax> tag to the datatable:

//columns

The listener function can either take no parameters, or it can take a SortEvent containing information which column is being sorted, and whether it's sorted ascending or descending. So you can react to the event.

Note the difference between PrimeFaces AJAX events and core JSF system events: You can catch a JSF system event using <f:ajax> or <p:ajax>, and as far as I know you can't catch an PrimeFaces AJAX event using <f:metatag> or by registering it in the JSF view root. The event families belong to different class hierarchies.

How can you make use of the events?

However, reacting to an event is a tad difficult. You are simply informed the event took place. That's fine for the select event. You are informed a row has been selected before the table is rendered. This comes in handy if you want to implement lazy loading of additional data, for example. Another example is shown in the PrimeFaces showcase cell editor demo.

Thing is, you can't veto the event. But that's what I needed when I discovered the data table events. Many users insist on using double clicks instead of single clicks, so I was looking for a way to prevent double clicks on the column header (causing the column to be sorted twice, which usually results in the original sort order). But there's simply no such thing as a abortProcessing method. On the server side, that is.

Luckily the event is also fired on the client side. Instead of trying to prevent the event on the server side, you can intercept it on the client side:

//columns

If you need to access back end data, you can use <p:remoteCommand> (see my article or check out the PrimeFaces showcase demo).

As for the double click problem, there may be an even simpler solution. I didn't test it yet, so please take it with a grain of salt. Simply set the minimum delay between two events to, say, half a second:[1]

//columns

Putting it all together

PrimeFaces keeps you informed if something happens to a data table. Reacting to the event sometimes requires clever thinking, but then, the <p:ajax> event is a remarkably flexible tool. For instance, I didn't mention the advanced properties of <p:ajax> yet: immediate and async.

Now I'm curious. How do you use the data table events? Drop a comment to tell me and your fellow readers!


Dig deeper

PrimeFaces manual (see section 3.2, roughly page 18, and 3.30, rougly page 167)

How to prevent double clicks in JSF 2

Oleg Varaksin on how to prevent multiple click in JSF


  1. Half a second is Microsofts's default time threshold to distinguish a double click from two single clicks.↩

Comments