我有一个自定义组件,如下所示
<custom:container>
<custom:checkbox index="0"/>
<custom:checkbox index="1"/>
</custom:container>
所以第一次调用encodeBegin时,它会显示hit tag <custom:container>
,它会尝试保存这个组件的client id,
private String containerClientId;
public void encodeBegin(FacesContext context, UIComponent component){
if (component instanceof ManyCheckboxContainer) {
containerClientId = component.getClientId(context);
return;
}
}
所以当我点击时 encodeEnd 会被调用<custom:checkbox index="0"/>
,就像这样
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>
所以在这种情况下,客户端ID(返回component.getClientId(context)
)<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,它搜索它的所有方面和子项,看看是否有任何组件匹配form3
,当然,没有一个会匹配,因为在我的结构中form3
是父级。回报也是f:subView
如此。null
这是 Mojarra 错误还是我做错了什么。我认为客户端 id 是相对于下一个 NamingContainer 祖先而不是一直到 NamingContainer 的根?我错了吗?