JSF2 复合组件:#{cc.childCount} 和 <composite:insertChildren/> 是互斥的吗?



我就是不明白:如果我希望我的复合组件插入子级,我使用<composite:insertChildren/>,但在这种情况下#{cc.childCount}总是返回0。另一方面,如果我不使用<composite:insertChildren/>,我总是得到正确的childCount,而不会渲染子级。为什么会发生这种情况?

在我的组件中,我只想在没有子级的情况下渲染一些"默认"面板,而在其他情况下不渲染它——行为类似于<ui:insert name="param_name">default value</ui:insert>。所以我需要insertChildren和childCount,它们似乎不能一起工作。

这是代码:

<my:test>
  <h:outputText value="child1" rendered="#{some.trueValue}"/>
  <h:outputText value="child2" rendered="#{some.trueValue}"/>
<my:test>

如果我使用下面的实现,我会得到如预期所呈现的2

<composite:implementation>
  <h:outputText value="#{cc.childCount}"/> 
</composite:implementation>

当使用insertChildren时,我得到渲染的子级和末尾的0

<composite:implementation>
  <composite:insertChildren/>
  <h:outputText value="#{cc.childCount}"/> 
</composite:implementation>

而我的目标是:

<composite:implementation>
  <composite:insertChildren/>
  <h:panelGroup rendered="#{cc.childCount == 0}">
    some default data
  </h:panelGroup> 
</composite:implementation>

有什么想法/解决办法吗?

将子项放在带有id的panelGroup中(例如子项)。

然后

#{component.findComponent('children').childCount}

将为您提供正确的值。祝你好运

来自cc:interstChildren文档:

使用页面中复合组件标记中的任何子组件或模板文本都将在该标记在节中的位置所指示的点处重新设置为复合组件的父级。

因此,通过使用<cc:insertChildren>,您实际上将子级从#{cc}组件移动到指定<cc:insertChildren>的组件,从而有效地使它们成为#{cc}的(曾孙)*孙。为了方便地接触这些搬迁的孩子,我使用<ui:fragment>作为家长:

<ui:fragment binding="#{childContainer}">
    <cc:insertChildren/>
</ui:fragment>

现在,您可以使用#{childContainer.childCount}来计算为复合组件指定的子级。不过,这个解决方案有点脆弱:由于绑定的原因,每个视图只能使用一次复合组件。这个问题当然可以通过将FacesComponent bean绑定到复合组件来解决。首先是豆子:

package com.stackoverflow.jsfinsertchildrenandcountexample;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
@FacesComponent(value = "myCompositeComponent")
public class MyCompositeComponent extends UINamingContainer {
    private UIComponent childContainer;
    public UIComponent getChildContainer() {
        return childContainer;
    }
    public void setChildContainer(UIComponent childContainer) {
        this.childContainer = childContainer;
    }
}

现在您可以将这个类绑定到您的复合组件:

<?xml version='1.0' encoding='UTF-8' ?>
<ui:component
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:cc="http://java.sun.com/jsf/composite"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    >
    <cc:interface componentType="myCompositeComponent">
    </cc:interface>
    <cc:implementation>
        I have #{cc.childContainer.childCount} children.
        <ui:fragment binding="#{cc.childContainer}">
            <cc:insertChildren/>
        </ui:fragment>
    </cc:implementation>
</ui:component>

现在您有了一个具有<cc:insertChildren>的复合组件,并可以直接访问这些子级。

编辑:纳入BalusC评论。

我也遇到了类似的问题。我切换到c:if,它起作用了,所以在你的情况下,它将是

<composite:implementation>
  <composite:insertChildren/>
    <c:if test="#{cc.childCount == 0}">
      some default data
    </c:if>
</composite:implementation>

相关内容

  • 没有找到相关文章

最新更新