【问题标题】:JSF2 composite components: are #{cc.childCount} and <composite:insertChildren/> mutually exclusive?JSF2 复合组件:#{cc.childCount} 和 <composite:insertChildren/> 是否互斥?
【发布时间】:2011-09-16 16:17:52
【问题描述】:

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

我想要在我的组件中做的就是在没有子级的情况下呈现一些“默认”面板,并且在其他情况下不呈现它 - 类似于 &lt;ui:insert name="param_name"&gt;default value&lt;/ui:insert&gt; 的行为。所以我需要两个似乎不能一起工作的 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>

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

【问题讨论】:

    标签: jsf jsf-2 composite-component


    【解决方案1】:

    将孩子放在一个有 id 的 panelGroup 中(例如孩子)。

    然后

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

    会给你正确的价值。祝你好运!

    【讨论】:

      【解决方案2】:

      来自 cc:insertChildren 文档:

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

      因此,通过使用&lt;cc:insertChildren&gt;,您实际上将子代从#{cc} 组件移动到您指定&lt;cc:insertChildren&gt; 的组件中,从而有效地使它们成为#{cc} 的(伟大的)* 孙子代。为了方便接触这些搬迁的孩子,我使用&lt;ui:fragment&gt; 作为父母:

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

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

      现在您有了一个带有&lt;cc:insertChildren&gt; 的复合组件,并且可以直接访问这些子组件。

      编辑:合并 BalusC 评论。

      【讨论】:

      • getFamily() 是不必要的,因为它已经在 UINamingContainer 中实现。只有当你实现NamingContainer接口,或者另一个UIComponent子类时,你确实需要自己指定。
      【解决方案3】:

      我遇到了类似的问题。我切换到c:if 并且它有效,所以在你的情况下它会是

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

      【讨论】:

        猜你喜欢
        • 2014-03-10
        • 1970-01-01
        • 1970-01-01
        • 2011-06-26
        • 2018-11-25
        • 2011-01-06
        • 1970-01-01
        • 2011-11-27
        • 2011-11-10
        相关资源
        最近更新 更多