PrimeFaces selectors
PrimeFaces integrates the jQuery Selector API (http://api.jquery.com/category/selectors) with the JSF component-referencing model. Partial processing and updating of the JSF components can be done using the jQuery Selector API instead of a regular server-side approach with findComponent()
. This feature is called the PrimeFaces Selector (PFS) API. PFS provides an alternative, flexible approach to reference components to be processed or updated partially. PFS is a client-side part of the PrimeFaces SEF, which provides both server-side and client-side extensions to make it easier to reference components.
In comparison with regular referencing, there is less CPU server load because the JSF component tree is not traversed on the server side in order to find client IDs. PFS is implemented on the client side by looking at the DOM tree. Another advantage is avoiding container limitations, and thus the cannot find
component exception—since the component we were looking for was in a different naming container.
The essential advantage of this feature, however, is speed. If we reference a component by an ID, jQuery uses document.getElementById()
, a native browser call behind the scene. This is a very fast call, much faster than that on the server side with findComponent()
. The second use case, where selectors are faster, is when we have a lot of components with the rendered
attributes set to true
or false
. The JSF component tree is very big in this case, and the findComponent()
call is time consuming. On the client side, only the visible part of the component tree is rendered as markup. The DOM is smaller than the component tree and its selectors work faster.
In this recipe, we will learn PFS in detail. PFS is recognized when we use @(...)
in the process
or update
attribute of AJAX-ified components. We will use this syntax in four command buttons to reference the parts of the page we are interested in.
How to do it…
The following code snippet contains two p:panel
tags with the input
, select
, and checkbox
components respectively. The first p:commandButton
component processes/updates all components in the form(s). The second one processes / updates all panels. The third one processes input
, but not select
components, and updates all panels. The last button only processes the checkbox
components in the second panel and updates the entire panel.
<p:messages id="messages" autoUpdate="true"/> <p:panel id="panel1" header="First panel"> <h:panelGrid columns="2"> <p:outputLabel for="name" value="Name"/> <p:inputText id="name" required="true"/> <p:outputLabel for="food" value="Favorite food"/> <h:selectOneMenu id="food" required="true"> ... </h:selectOneMenu> <p:outputLabel for="married" value="Married?"/> <p:selectBooleanCheckbox id="married" required="true" label="Married?"> <f:validator validatorId="org.primefaces.cookbook. validator.RequiredCheckboxValidator"/> </p:selectBooleanCheckbox> </h:panelGrid> </p:panel> <p:panel id="panel2" header="Second panel"> <h:panelGrid columns="2"> <p:outputLabel for="address" value="Address"/> <p:inputText id="address" required="true"/> <p:outputLabel for="pet" value="Favorite pet"/> <h:selectOneMenu id="pet" required="true"> ... </h:selectOneMenu> <p:outputLabel for="gender" value="Male?"/> <p:selectBooleanCheckbox id="gender" required="true" label="Male?"> <f:validator validatorId="org.primefaces.cookbook. validator.RequiredCheckboxValidator"/> </p:selectBooleanCheckbox> </h:panelGrid> </p:panel> <h:panelGrid columns="5" style="margin-top:20px;"> <p:commandButton process="@(form)" update="@(form)" value="Process and update all in form"/> <p:commandButton process="@(.ui-panel)" update="@(.ui-panel)" value="Process and update all panels"/> <p:commandButton process="@(.ui-panel :input:not(select))" update="@(.ui-panel)" value="Process inputs except selects in all panels"/> <p:commandButton process="@(#panel2 :checkbox)" update="@(#panel2)" value="Process checkboxes in second panel"/> </h:panelGrid>
Note
In terms of jQuery selectors, regular input field, selection, and checkbox controls are all inputs. They can be selected by the :input
selector.
The following screenshot shows what happens when the third button is pushed. The p:inputText
and p:selectBooleanCheckbox
components are marked as invalid. The h:selectOneMenu
component is not marked as invalid although no value was selected by the user.
How it works…
The first selector from the @(form)
first button selects all forms on the page. The second selector, @(.ui-panel)
, selects all panels on the page as every main container of PrimeFaces' p:panel
component has this style class. Component style classes are usually documented in the Skinning section in PrimeFaces User's Guide (http://www.primefaces.org/documentation.html). The third selector, @(.ui-panel :input:not(select))
, only selects p:inputText
and p:selectBooleanCheckbox
within p:panel
. This is why h:selectOneMenu
was not marked as invalid in the preceding screenshot. The validation of this component was skipped because it renders itself as an HTML select
element. The last selector variant, @(#panel2 :checkbox)
, intends to select p:selectBooleanCheckbox
in the second panel only.
Tip
In general, it is recommended that you use Firebug (https://getfirebug.com) or a similar browser add-on to explore the generated HTML structure when using jQuery selectors.
A common use case is skipping validation for the hidden fields. Developers often hide some form components dynamically with JavaScript. Hidden components get validated anyway, and the form validation can fail if the fields are required or have other validation constraints. The first solution would be to disable the components (in addition to hiding them). The values of disabled fields are not sent to the server. The second solution would be to use jQuery's :visible
selector in the process
attribute of a command component that submits the form.
There's more…
PFS can be combined with regular component referencing as well, for example, update="compId1 :form:compId2 @(.ui-tabs :input)"
.
The PrimeFaces Cookbook Showcase application
This recipe is available in the demo web application on GitHub (https://github.com/ova2/primefaces-cookbook/tree/second-edition). Clone the project if you have not done it yet, explore the project structure, and build and deploy the WAR file on application servers compatible with Servlet 3.x, such as JBoss WildFly and Apache TomEE.
The showcase for the recipe is available at http://localhost:8080/pf-cookbook/views/chapter1/pfs.jsf
.