Составные компоненты JSF2: являются ли {{cc.childCount} и <композит: insertChildren /> взаимоисключающими? - PullRequest
7 голосов
/ 16 июня 2011

Я просто не понимаю: если я хочу, чтобы мой составной компонент вставлял дочерние элементы, я использую <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>

Есть идеи / обходные пути?

Ответы [ 3 ]

5 голосов
/ 17 июня 2011

Поместите детей в группу Panel с идентификатором (например, дети).

Тогда

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

даст вам правильное значение.Удачи!

3 голосов
/ 24 июля 2015

Из документации cc: insertChildren:

Любые дочерние компоненты или текст шаблона в теге составного компонента на странице использования будут заново объединены в составной компонент в точке, указанной этим тегом.размещение в разделе.

Таким образом, используя <cc:insertChildren>, вы фактически перемещаете дочерние элементы из компонента #{cc} в компонент, в котором вы указали <cc:insertChildren>, эффективно превращая их (великих) * внуков#{cc}.Чтобы получить легкий доступ к этим перемещенным дочерним элементам, я использую <ui:fragment> в качестве родителя:

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

Теперь вы можете использовать #{childContainer.childCount} для подсчета дочерних элементов, указанных вами для составного компонента.Это решение немного хрупко: из-за привязки вы можете использовать ваш составной компонент только один раз для каждого представления.Эта проблема, конечно, может быть решена путем привязки bean-компонента 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.

1 голос
/ 26 апреля 2012

У меня была похожая проблема. Я переключился на c:if, и это сработало, поэтому в вашем случае это будет

<composite:implementation>
  <composite:insertChildren/>
    <c:if test="#{cc.childCount == 0}">
      some default data
    </c:if>
</composite:implementation>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...