JSF 复合组件 <f:ajax> 包含未知 id - 无法在组件的上下文中找到它

Posted

技术标签:

【中文标题】JSF 复合组件 <f:ajax> 包含未知 id - 无法在组件的上下文中找到它【英文标题】:JSF Composite component <f:ajax> contains an unknown id - cannot locate it in the context of the component 【发布时间】:2012-04-09 03:56:13 【问题描述】:

我正在尝试使用 f:ajax 从复合组件事件更新父组件。

复合组件在这里:

<cc:interface>
    <cc:attribute name="update" />
    <cc:attribute name="customid" required="true"/>
    <cc:attribute name="val" required="true"/>
    <cc:attribute name="selectedvalue" required="true"/>
</cc:interface>
<cc:implementation>
    <h:panelGrid columns="2" style="font-size: 10px" >
        <p:selectOneMenu id="#cc.attrs.customid value="#cc.attrs.selectedvalue">
            <f:selectItems value="#cc.attrs.val"/>
            <f:ajax event="change" render="#cc.attrs.update" />
        </p:selectOneMenu>
        <p:commandButton type="button" icon="ui-icon-plus" onclick="dlg.show();" />
    </h:panelGrid>
</cc:implementation>

现在使用这个组件时如下:

<h:form>
    <ez:combo customid="make" val="#vehicleBean.makes" selectedvalue="#vehicleBean.vehicle.make" update="model"  />
    <p:selectOneMenu id="model" value="#vehicleBean.vehicle.model">
        <f:selectItems value="#vehicleBean.models" />
    </p:selectOneMenu>
</h:form>

我收到以下错误:

包含未知 id 'model' - 无法在组件 make 的上下文中找到它

【问题讨论】:

不是 错误(缺少 ) 【参考方案1】:

由于要更新的​​组件在 cc 之外,因此您必须以不同的方式对其进行处理。首先给你的表单一个id:

<h:form id="myform">

然后像这样从您的 cc 中寻址目标组件:

render=":myform:model"

注意结尾的冒号,它让 JSF 从文档根目录中搜索属性。

【讨论】:

仍然无法找到.. 包含未知 id ':myform:model' 在浏览器中检查生成的 html 源代码是否正确。也许您的文档树中有另一个 NamingContainer,但您没有在问题中显示【参考方案2】:

前段时间我遇到了同样的问题,只是为了提供信息,我检查了 jsf mojara 实现的源代码;这似乎是如何工作的: ajaxBehaviorRendered 类,当遇到要渲染的 f:ajax 元素时,通过其方法 getResolvedId:

分析 render 属性的内容:

private static String getResolvedId(UIComponent component, String id) 

        UIComponent resolvedComponent = component.findComponent(id);
        if (resolvedComponent == null) 
...

重点是findComponent方法:这个需要base component base作为在组件树中查找的strat point。如果标识符以字符“:”开头,则组件基是 viewRoot。



    UIComponent base = this;
     if (expr.charAt(0) == sepChar) 
        // Absolute searches start at the root of the tree
        while (base.getParent() != null) 
            base = base.getParent();
         
        expr = expr.substring(1);
    

否则,基本组件是当前组件最接近的 NamingContainer 类型的父组件(即,您定义 ajax 组件的复合组件)。



    //Treat remainder of the expression as relative
    else if (!(base instanceof NamingContainer)) 
        // Relative expressions start at the closest NamingContainer or root
        while (base.getParent() != null) 
            if (base instanceof NamingContainer) 
                break;
            
            base = base.getParent();
        
    

然后,在这两种情况下,它都会从这个开始搜索具有给定标识符的组件。

此行为是 jsf 指定的行为。

从我的观点来看,如果您需要引用组合之外的组件,则必须定义完整的名称,使用前缀“:”,后跟“cc.clientId”属性。

【讨论】:

非常有趣的一点,谢谢。顺便说一句,为什么我们不能将 render 属性指定为 :client_id 省略父表单 ID? 我已经 2 年没有与 JSF 合作了,我希望我不会回答一些愚蠢的问题。据我记得(但我不太确定),JSF 生命周期在处理组件树并在表单中找到组件时,会自动在该组件的标识符前面加上表单的标识符。因此,它无法解析“:client_id”,因为它的真实标识符是“form_id:client_id”。但它应该被审查,因为我在过去的 2 年中失去了对 JSF 的关注。 所以,是的,componentSEarch 算法需要组件的完整路径。你不知道这是否是 Mojarra 实现的特定事物吗? 这是个好问题。 mojarra 实现是来自 sun(最初是 JSF-RI)的实现。它将需要审查有关 JSF 的 JSR 并检查此行为是否已明确定义或留给实现。从使用另一种实现(例如 Apache 的 MyFaces)的人那里获得知识也会很有趣

以上是关于JSF 复合组件 <f:ajax> 包含未知 id - 无法在组件的上下文中找到它的主要内容,如果未能解决你的问题,请参考以下文章

JSF 2 - 如何将 Ajax 侦听器方法添加到复合组件接口?

JSF 自定义组件:如何获取 <f:ajax /> 的属性

jsf ajax 部分渲染

JSF 复合组件值和 <c:if> [重复]

JSF 2 复合组件渲染问题

如何使用 JSF 复合组件使页面上的 id 唯一?