1

Mojarra 2.1.

The question is actually about the component finding algorithm.

I have the following UIRepeat:

<h:form id="frm">

    <ui:repeat id="repeater" value="#{bean.values}" var="v">
        <h:panelGroup id="pg">
            <!-- content -->
            <h:selectBooleanCheckbox id="cb" value="#{bean.v}">
                <f:ajax event="change" listener="#{bean.listener()}" render=":frm:repeater:pg" />
           </h:selectBooleanCheckbox>
           <!-- another content -->
        </h:panelGroup>
    </ui:repeat>

</h:form>

Now consider the method AjaxBehaviorRenderer#getResolvedId:

private static String getResolvedId(UIComponent component, String id) {

        UIComponent resolvedComponent = component.findComponent(id);
        if (resolvedComponent == null) {
            // RELEASE_PENDING  i18n
            throw new FacesException(
                "<f:ajax> contains an unknown id '"
                + id
                + "' - cannot locate it in the context of the component "+component.getId());
        }

        return resolvedComponent.getClientId();
    }

This method is intended to resolve the render attribute value to a component. Now, in the debugger I found that the method is being called with the following parameters in my case:

component = the instance of the HtmlSelectBooleanCheckbox
id = :frm:repeater:pg

Now, the method component.findComponent(id) returns the component which has clientId - frm:repeater:0:pg. But invoking the method as component.findComponent(":frm:repeater:0:pg") returns null.

Why? I expected the result would be the same. What did I miss?

St.Antario
  • 26,175
  • 41
  • 130
  • 318

1 Answers1

2

This was as per impl issue 2958 "fixed" in Mojarra 2.2.5 where they simply removed that nullcheck altogether instead of improving it by stripping the iteration index. Since then, one can specify an arbitrary client ID and not ever trigger an exception. I've created API issue 1372 and proposed a fix to address this.

This thus means, that since Mojarra 2.2.5 you can ajax-update a specific <ui:repeat> or <h:dataTable> iteration round, provided that the model is properly preserved (i.e. it is view scoped).

<h:form id="form">
    <ui:repeat id="list" value="#{['one','two','three']}" var="item">
        <h:outputText id="item" value="#{item}" /><br/>
    </ui:repeat>

    <h:commandButton value="Update second item">
        <f:ajax render=":form:list:1:item" />
    </h:commandButton>
</h:form>

But this also means, that since Mojarra 2.2.5, you will never face the well known "<f:ajax> contains an unknown id 'foo' cannot locate it in the context of the component 'bar'" error, which is confusing and bad for starters.

See also:


Unrelated to the concrete problem, in your specific case, you can also just do render="pg" instead of render=":frm:repeater:pg", as the render target component is in the very same naming container parent component as the execute source component.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • So, before Mojarra 2.2.5 the `component.findComponent(:frm:repeater:pg)` returns a component related to the specific iteration item which is being determined by the `component` itself, right? – St.Antario Aug 26 '15 at 08:45
  • This is regardless of Mojarra version. The false exception occurs only before 2.2.5. – BalusC Aug 26 '15 at 08:48
  • Ah, now I see that, thank you. In the Mojarra 2.2.12 We just check if the specified id is a "global id" first. If so, we return the `id.substring(1)`. If not, then just return the id. I thought that it was implemented as you noted in the comment _We could alternatively improve findComponent() spec and algorithm to cover the iteration index._ – St.Antario Aug 26 '15 at 09:44