我有一个自定义组件,如下所示
<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的根目录?我错了吗?