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

Understanding ui:repeat client id and component finding

莫哈拉 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();
    }

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

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

现在,方法 component.findComponent(id) returns 具有 clientId - frm:repeater:0:pg 的组件。但是调用方法为 component.findComponent(":frm:repeater:0:pg") returns null

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

这是根据 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 提出的解决方案。

这意味着,从 Mojarra 2.2.5 开始,您可以 ajax-更新特定的 <ui:repeat><h:dataTable> 迭代轮次,前提是模型得到妥善保存(即它是视图范围内的)。

<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 开始,您将永远不会遇到众所周知的 " contains an unknown id 'foo' cannot locate它在组件 'bar'" 错误的上下文中,这对初学者来说是令人困惑和不利的。

另请参阅:

  • How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

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