- 4 minutes read

Since JSF 2.2, JSF programs frequently use native JavaScript widgets. Of course, these widgets (and even some JSF widgets) know nothing about the way JSF uses AJAX. But fear not: if you're using BootsFaces, PrimeFaces or OmniFaces, it's easy to add AJAX to these widgets.

Examples

Let me give you one or two real-life examples before telling you how to solve the problem.

As far as I know, there's no JSF library supporting Material Design natively. BootsFaces offers a reasonably good approximation in disguise of its Patternfly theme. But it's not the real thing. Luckily, since JSF 2.2, that's not a big deal. Pass-through-attributes and pass-through-element give you all the freedom you need to combine JSF with Material Design. The only question remaining how to trigger an AJAX request.

Another use case popped up recently when a BootsFaces user asked how to add a "close" button to a tab. Adding the button to the tab turned out to be simply a matter of adding a facet:

... (tab content) ...

The only problem was the onclick attribute. For some reason unknown, the JSF AJAX engine doesn't cover the facet. Actually, that may not even be an exotic case. Many JSF components are so versatile it's difficult to add AJAX to every part of them.

RemoteCommand to the rescue

JSF AJAX may not cover the widget, but usually, JavaScript does. The BootsFaces snippet above shows the idea: even if onclick can't call a JSF bean method directly, it still can call a JavaScript method. That JavaScript method, in turn, can be a <b:remoteCommand />.

The BootsFaces <b:remoteCommand /> calls a JSF back-end bean method and updates a part of the DOM tree:

As you can see, the remote command even accepts parameters and passes them to the back-end bean. The JavaScript method takes the parameters as a standard parameter list. There are no surprises here. However, you'll see in a minute that OmniFaces and PrimeFaces follow a different approach. In the case of BootsFaces, you have to define the parameters as a comma-separated list in the <b:remoteCommand /> tag.

The parameters aren't passed directly as method parameters to the Java bean method. Instead, they can be accessed using the parameter map of the request:

public void removeTab() { String title = FacesContext.getCurrentInstance().getExternalContext() .getRequestParameterMap().get("title"); ... } }

PrimeFaces

The PrimeFaces remote command is similar:

The chief difference is that the parameters are an array of JSON objects, like so:

divideNumbers([{name:'divisor', value:12}, {name:'divident', value:6}]);

OmniFaces

The OmniFaces counterpart of the remote command is called <o:commandScript /> and follows the core JSF tradition of AJAX:

Another difference is that the JavaScript method accepts parameters as a standard JSON object:

divideNumbers({ divisor: "12", divident: "6" });

Wrapping it up

It's quite a challenge for a JSF component author to add AJAX at every interesting place. Nobody can predict what the users (you!) are going to do with the fancy new widget. Luckily, remote commands offer a simple (if slightly verbose) way out. Plus, they can add JSF AJAX to native JavaScript widgets the authors of which never dreamt of JSF. Don't ask them: many JavaScript developers aren't that fond of JSF, so they might not be happy at all to learn their pet library is used in a JSF application. :)


Comments