Привязка экземпляра управляемого компонента к составному компоненту

У меня есть составной компонент (collapsiblePanel). Компонент использует "разборный" компонент для обеспечения функции переключения. Когда я использую один и тот же компонент несколько раз на странице, каждый экземпляр компонента привязывается к одному и тому же экземпляру компонента. Как я могу добиться чего-то вроде bean-компонента с областью действия компонента?

collapsibleTemp.xhtml:

<cc:interface>
    <cc:attribute name="model" required="true">
        <cc:attribute name="collapsed" required="true" />
        <cc:attribute name="toggle" required="true"
            method-signature="java.lang.String f()" />
    </cc:attribute>
    <cc:actionSource name="toggle" />
    <cc:facet name="header" />
    <cc:facet name="body" />
</cc:interface>
<cc:implementation>
    <h:panelGroup layout="block" styleClass="collapsiblePanel-header">
        <h:commandButton id="toggle" action="#{cc.attrs.model.toggle}"
            styleClass="collapsiblePanel-img"
            image="#{cc.attrs.model.collapsed ? '/resources/images/plus.png' : '/resources/images/minus.png'}" />
        <cc:renderFacet name="header" />
    </h:panelGroup>
    <h:panelGroup layout="block" rendered="#{!cc.attrs.model.collapsed}">
        <cc:insertChildren />
        <cc:renderFacet name="body"></cc:renderFacet>
    </h:panelGroup>
    <h:outputStylesheet library="css" name="components.css" />
</cc:implementation>

Поддерживающий компонент:

@ManagedBean
@ViewScoped
public class Collapsible {

    private boolean collapsed = false;

    public boolean isCollapsed() {
        return collapsed;
    }

    public void setCollapsed(boolean collapsed) {
        this.collapsed = collapsed;
    }

    public String toggle() {
        collapsed = !collapsed;
        return null;
    }

}

Использование страницы

<h:form id="someid">
    <jl:collapsibletemp id="collapsiblePanel1" model="#{collapsible}">
        <f:facet name="header">
            <h3>
                <h:outputText value="Collapsible information" />
            </h3>
        </f:facet>
        <f:facet name="body">
            <h:outputText value="do something....." />
        </f:facet>
        <p />
    </jl:collapsibletemp>

    <jl:collapsibletemp id="collapsiblePanel2" model="#{collapsible}">
        <f:facet name="header">
            <h3>
                <h:outputText value="Collapsible information" />
            </h3>
        </f:facet>
        <f:facet name="body">
            <h:outputText value="do some tabbing" />
        </f:facet>
        <p />
    </jl:collapsibletemp>

    <jl:collapsibletemp id="collapsiblePanel3" model="#{collapsible}">
        <f:facet name="header">
            <h3>
                <h:outputText value="Collapsible information" />
            </h3>
        </f:facet>
        <f:facet name="body">
            <h:outputText value="notice board" />
        </f:facet>
        <p />
    </jl:collapsibletemp>
</h:form>

person Smith    schedule 06.07.2011    source источник


Ответы (1)


Вы можете использовать атрибут componentType для <cc:interface>, чтобы определить «поддерживающий компонент».

E.g.

<cc:interface componentType="collapsiblePanel">
    ...
</cc:interface>
<cc:implementation>
    ...
    <h:commandButton action="#{cc.toggle}" ... />
    ...
    <h:panelGroup rendered="#{!cc.collapsed}" ...>
    ...
</cc:implementation>

только с com.example.components.CollapsiblePanel

@FacesComponent(value="collapsiblePanel") // To be specified in componentType attribute.
public class CollapsiblePanel extends UINamingContainer { // Important! Must extend UINamingContainer.

    private boolean collapsed;

    public void toggle() {
        collapsed = !collapsed;
    }

    public boolean isCollapsed() {
        collapsed;
    }

}

Однако если вы хотите иметь несколько таких компонентов, вам следует объявить физически отдельные их экземпляры в представлении. Если это должно происходить динамически, вам нужно использовать <c:forEach> для создания их физически отдельных экземпляров вместо <ui:repeat> с одним компонентом. В противном случае вам нужно сопоставить все состояния collapsed по идентификатору клиента внутри файла Map<String, Boolean>. См. также пример и дополнительную справочную информацию Получение один и тот же экземпляр `componentType` в составном компоненте при каждом использовании

person BalusC    schedule 06.07.2011
comment
Это решение работает частично. Когда я переключаю один компонент, другой компонент также переключается. Я вручную объявил компоненты 3 раза. Когда я включаю какой-либо один компонент, другие 2 также переключаются. ‹jl:collapsibletemp id=collapsiblePanel1›‹/jl:collapsibletemp› ‹jl:collapsibletemp id=collapsiblePanel2›‹/jl:collapsibletemp› ‹jl:collapsibletemp id=collapsiblePanel3›‹/jl:collapsibletemp› Спасибо за вашу помощь. Пожалуйста, дайте мне знать, что я могу сделать, чтобы сделать эти компоненты полностью независимыми друг от друга. - person Smith; 07.07.2011
comment
Это именно то, что я уже предсказал и рассказал в последнем абзаце своего ответа. Используйте <c:forEach> или сохраните логические значения на карте с идентификатором клиента в качестве ключа. - person BalusC; 07.07.2011
comment
Я внес изменения, как вы предложили. Но все равно это не работает. Используя страницу: ‹js:forEach items=#{widgets.windows} var=window› ‹jl:collapsibletemp id=collapsiblePanel#{window.name} /› ‹/js:forEach› @ManagedBean(name=widgets) общедоступный класс виджетов { public List‹Window› getWindows() { if(windows == null){ windows = new ArrayList‹Window›(); windows.add(новое окно(один, один заголовок, одно тело)); windows.add(новое окно(два, два заголовка, два тела)); } вернуть окна; Даже после добавления свернутых состояний на карту они не ведут себя как независимые компоненты. - person Smith; 08.07.2011
comment
@FacesComponent(value = "collPanelTwo") class CollPanel extends UICompBase implements NContainer { public void toggle(ActionEvent evt) { collapsed = !collapsed; testMap.put(getClientId(), isCollapsed()); } public boolean isCollapsed() { return testMap.get(getClientId()); } ИСПОЛЬЗОВАНИЕ СТРАНИЦЫ ‹jl:collapsibleComponent clientId=one›facets... ‹jl:collapsibleComponent clientId=two›facets... Я вручную добавил 2 компонента в представления. Они не ведут себя как независимые компоненты. Я также пробовал ‹jstl:forEach, но он никогда не отображался как независимый компонент. - person Smith; 11.07.2011
comment
Спасибо BalucS. Мне пришлось немного поработать, чтобы заставить его работать. Я использовал stateHelper для сохранения состояния. - person Smith; 21.07.2011