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

时间:2012-03-25 08:01:18

标签: ajax jsf-2 composite-component

我正在尝试使用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“模型” - 无法在组件make

的上下文中找到它

2 个答案:

答案 0 :(得分:15)

由于要更新的​​组件不在cc中,因此您必须以不同的方式解决它。首先给你的表单一个id:

<h:form id="myform">

然后从cc中解决目标组件:

render=":myform:model"

注意尾随冒号,它允许JSF从文档根目录中搜索属性。

答案 1 :(得分:4)

前一段时间我遇到同样的问题,仅仅是为了获取信息,我检查了jsf mojara实现的来源;这是它似乎如何工作: 类ajaxBehaviorRendered在遇到要渲染的 f:ajax 元素时,通过其方法getResolvedId分析 render 属性的内容:


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

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

重点是方法findComponent:这个方法需要基础组件库作为在组件树中搜索的策略点。如果标识符以char“:”开头,则组件库是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'属性。