当复合组件内部时,Mojarra findComponent为有效id返回null

时间:2012-08-09 22:51:54

标签: jsf jsf-2 mojarra

我有一个自定义组件,如下所示

<custom:container>
    <custom:checkbox index="0"/>
    <custom:checkbox index="1"/>
</custom:container>

所以当encodeBegin第一次调用时,它会显示标记<custom:container>,它会尝试保存此组件的cliend id,

private String containerClientId;
public void encodeBegin(FacesContext context, UIComponent component){
    if (component instanceof ManyCheckboxContainer) {            
        containerClientId = component.getClientId(context);
        return; 
    }
}

所以当我点击<custom:checkbox index="0"/>时会调用encodeEnd,就像这样

public void encodeEnd(FacesContext context, UIComponent component) throws IOException {

    ...

    if (component instanceof Checkbox) {
        renderCheckbox(context, (Checkbox) component);
    } 
    ...
}

protected void renderCheckbox(FacesContext facesContext, InforRadio radio) throws IOException {
    ...
    UIComponent uiComponent = radio.findComponent(containerClientId);
    if(uiComponent == null){
         //throw error
    }
    ...
}

如果我在复合组件中没有这个自定义组件,那么一切都很好,但是一旦我把它放在复合组件中,radio.findComponent(containerClientId);就会返回null。这是mojarra的一个错误吗?我在2.1.10和2.1.11下测试了这个,行为相同。

修改
所以我把它拿回来,当我的自定义组件在两个嵌套的NamingContainer内时发生这种行为,所以像这样的事情

<h:form id="myForm">
    <f:subView id="myView">
        <custom:container id="myCustom">
            <custom:checkbox index="0"/>
            <custom:checkbox index="1"/>
        </custom:container>
    </f:subView>
</h:form>

所以在这种情况下,component.getClientId(context)的客户端ID(<custom:container>返回)为myForm:myView:myCustom,但在Mojarra中,findComponent方法有此

public UIComponent findComponent(String expr) {
     ...

     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();
     }
     ...
}

所以它会查找下一个祖先NamingContainer,在我的情况下是f:subView而不是h:form。然后它解析客户端ID,循环遍历它,每次将id的一部分传递给UIComponent findComponent(UIComponent base, String id, boolean checkId)。所以第一次进入时,此方法将form3作为id并且当前UIComponent为f:subView,它搜索其所有facet和子项以查看是否有任何组件匹配form3,当然,none将匹配因为form3是我结构中f:subView的父级。所以null回来了。这是Mojarra的错误还是我做错了。我认为客户端ID是从下一个NamingContainer祖先相对而不是一直到NamingContainer的根目录?我错了吗?

1 个答案:

答案 0 :(得分:3)

在阅读docs之后,我觉得Mojarra做对了。

根据文档,如果要从树的根目录进行“绝对”搜索,则应在搜索表达式前面放置一个分隔符(冒号)。 否则,它将从组件本身进行相对搜索,如果它是NamingContainer或第一个父级是NamingContainer。

顺便说一句:我链接的文档似乎与随规格分发的官方文档相同。官方规格为here