PrimeFaces Selector Framework: Use jQuery in JSF Expressions

Posted on Posted in JSF, simpliying JSF

These days I re-discovered a really cool PrimeFaces feature. It’s one of those features that raise JSF to another level. I’m talking about the PrimeFaces Selector API which allows you to use arbitrary jQuery expression instead of ideas.

For instance, this feature comes in handy with BabbageFaces, my JSF plugin that allows and even encourages you to do AJAX without IDs. In most cases it suffices to update the @form. However, when I started to port the Pet Store demo application written by Antonio Goncalves to AJAX and BabbageFaces, I discovered the language selector. Switching from – say – English to French requires you to update every text on the screen, no matter whether it’s inside or outside a form.

With standard JSF things get tedious. You could assign an ID to the body and update the body. But this also means re-running the onLoad script. Sometimes you’d rather avoid this. PrimeFaces enables you to update every node within the body (excluding the body tag itself) using a simple jQuery expression:

<prime:commandLink action="#{localeBean.setLanguage('es')}" 
                   immediate="true" 
                   update="@(body > *)">
    <h:outputText value="&nbsp;EspaƱol" />
</prime:commandLink>

The expression update="@(body > *)" is evaluated on the client. So you can express a lot of queries you cannot express on the server side. @(body > *) is translated to a list of IDs that are to be updated:

PrimeFaces Selector Framework - using jQuery in updates

There’s a catch.

The jQuery expression may be evaluated on the client, but it’s evaluated to IDs that are needed on the server side. Those IDs have to belong to JSF components. Many people like to mix ordinary HTML code with JSF facelets. That’s not a good idea in this case. Standard HTML divs aren’t JSF components, so they are never updated by an JSF button, no matter whether they bear an ID or not. Even worse: the jQuery expression finds the ID, so everything seems to be OK when you inspect the HTTP request. But there’s no counterpart on the server side, so the ID is gracefully ignored.

In general I suggest to use facelets exclusively. If you can’t avoid using pure HTML for some reason you can embed it in a <h:panelGroup>. JSF generates an extra div. Beware: You can’t omit defining the ID. BabbageFaces adds an ID to the HTML code, but again: that ID is available on the client side only. So the solution goes along these lines:

<h:body>
    <h:panelGroup id="HeaderPanelID" layout="block">
        ... (pure HTML code allowed) ...
    </h:panelGroup>
    <h:panelGroup id="ContentPanelID" layout="block">
        ... (pure HTML code allowed) ...
    </h:panelGroup>
    <h:panelGroup id="FooterPanelID" layout="block">
        ... (pure HTML code allowed) ...
    </h:panelGroup>

Further reading:

original announcement on PrimeFaces blog
a StackOverflow discussion on how PFS works behind the scenes


Leave a Reply

Your email address will not be published.