了解ui:重复客户端ID和组件查找

时间:2015-08-26 06:50:06

标签: jsf jsf-2 mojarra

Mojarra 2.1。

问题实际上是关于组件查找算法。

我有以下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>

现在考虑方法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();
    }

此方法旨在将render属性值解析为组件。现在,在调试器中,我发现在我的情况下使用以下参数调用该方法:

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

现在,方法component.findComponent(id)会返回包含clientId - frm:repeater:0:pg的组件。但是以component.findComponent(":frm:repeater:0:pg")方式调用该方法会返回null

为什么呢?我预计结果会是一样的。我错过了什么?

1 个答案:

答案 0 :(得分:2)

根据impl issue 2958&#34;已修复&#34;在Mojarra 2.2.5中,他们完全删除了那个nullcheck而不是通过剥离迭代索引来改进它。从那时起,人们可以指定任意客户端ID,而不会触发异常。我创建了API issue 1372并提出了解决此问题的方法。

这意味着,自Mojarra 2.2.5起,您可以ajax更新特定的<ui:repeat><h:dataTable>迭代轮,前提是模型已正确保留(即它是视图范围)。 / p>

<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>

但这也意味着,自从Mojarra 2.2.5开始,你永远不会面对众所周知的&#34;&lt; f:ajax&gt;包含一个未知的ID&#39; foo&#39;无法在组件&#39; bar&#39;&#34; 错误的上下文中找到它,这对于初学者来说是令人困惑和不好的。

另见:

无关具体问题,在您的具体情况下,您也可以只执行render="pg"而不是render=":frm:repeater:pg",因为渲染目标组件的命名方式完全相同容器父组件作为执行源组件。