How do PrimeFaces Selectors as in update="@(.myClass)" work?

John N picture John N · Nov 19, 2013 · Viewed 54.8k times · Source

I don't understand how PrimeFaces selectors (PFS) work.

<h:outputText value="#{bean.text1}" styleClass="myClass" />
<p:commandButton update="@(.myClass)" />

I can use it. And I think it's a fantastic tool although it doesn't function always for me. The .myClass is client side jQuery selector. How does JSF on server side know what to update?

I can understand how normal JSF ID selectors work.

<h:outputText value="#{bean.text1}" id="textId" />
<p:commandButton update="textId" />

The textId references an ID of component in the component tree as defined in XHTML file in server side. So I can understand how JSF finds the right component.

But if you are using primefaces selectors, the client side jQuery selectors are used. How does JSF know which component has to be updated? Sometimes I have problems with PFS. It doesn't seem to function always for me. Is there something what you should keep in mind if you are using PFS?

Answer

BalusC picture BalusC · Nov 19, 2013

You probably already know that PrimeFaces is using jQuery under the covers. PrimeFaces Selectors are based on jQuery. Anything which you specify in @(...) will be used as jQuery selector on the current HTML DOM tree. For any found HTML element, which has an ID, exactly this ID will ultimately be used in the update.

Basically, for a update="@(.myclass)", PrimeFaces will under the covers roughly do this:

var $elements = $(".myclass");
var clientIds = [];

$.each($elements, function(index, element) {
    if (element.id) {
        clientIds.push(":" + element.id);
    }
});

var newUpdate = clientIds.join(" "); // This will be used as `update` instead.

So, in case of e.g.

<h:form id="formId">
    <h:outputText id="output1" styleClass="myclass" ... />
    <h:outputText styleClass="myclass" ... />
    <h:outputText id="output3" styleClass="myclass" ... />
</h:form>

this command button update

<p:commandButton ... update="@(.myclass)" />

will end up with exactly the same effect as

<p:commandButton ... update=":formId:output1 :formId:output3" />

Note that this also works for autogenerated IDs. I.e. the <h:form id> is not mandatory.


Sometimes I have a problems with PFS. Is there something what you are should keep in mind if you are using PFS ?

It can happen that you selected "too much" (e.g. @(form) doesn't select current form, but all forms, exactly like $("form") in jQuery!), or that you actually selected nothing (when the desired HTML DOM element has actually no ID). Investigating element IDs in the HTML DOM tree and the request payload in the HTTP traffic monitor the should give clues.

The desired elements in the HTML DOM tree must have an (autogenerated) ID. The javax.faces.partial.render request parameter in the HTTP traffic monitor must contain the right client IDs. The element's rendered attribute in the JSF component tree must evaluate true during update. Etcetera.

In your particular example, the <h:outputText> won't end up in the generated HTML output with any ID. Assigning it an id should solve your problem with updating it.

So, this example won't work

<h:form>
    <h:outputText value="#{bean.text1}" styleClass="myClass" />
    <p:commandButton value="Update" update="@(.myClass)" /> 
</h:form>

but this example will work (note that assigning the form an ID is not necessary):

<h:form>
    <h:outputText id="myText" value="#{bean.text1}" styleClass="myClass" />
    <p:commandButton value="Update" update="@(.myClass)" /> 
</h:form>