Как сделать повторно используемый компонент в JSF?

Я хотел бы иметь повторно используемый компонент ui, привязанный к модели.

Например:

  • У меня есть selectonemenu, который прикован к другому selectonemenu (например, отдел → подразделение).
  • Хотелось бы сделать это составным компонентом
  • Этот составной компонент будет привязан к определенному JSF Bean

Я думаю, что эта идея работает, если im использует только один составной компонент.

Но это не сработает, если я использую более одного составного компонента того же типа, так как составной составной JSF Bean будет тем же самым (в этом примере im использует область просмотра), и будет делиться состоянием между одним или несколькими составными компонентами.

Это один пример, иллюстрирующий мое замешательство. В этом случае Page1.xhtml(с основной моделью Page1Bean.java) использует 2 составных компонента (которые обрабатываются JSF Bean MyCompositeComponent.java)

Компонентный компонент будет выглядеть примерно так:

<!-- one composite component that has 2 chained selectOneMenus -->
<h:selectOneMenu
    ...
    value="#{myCompositeComponentBean.firstComboValue}"
    valueChangeListener="#{myCompositeComponentBean.yyy}">
    <f:ajax event="valueChange" execute="@this" ... />
    <f:selectItem itemLabel="Choose one .." noSelectionOption="true" />
    <f:selectItems value="#{myCompositeComponentBean.firstComboList}" .... />
</h:selectOneMenu>
<h:selectOneMenu
    ...
    value="#{myCompositeComponentBean.secondComboValue}"
    valueChangeListener="#{myCompositeComponentBean.bbb}">
    <f:selectItem itemLabel="Choose one .." noSelectionOption="true" />
    <f:selectItems value="#{myCompositeComponentBean.secondComboList}" .... />
</h:selectOneMenu>

И составной компонент JSF Bean будет выглядеть следующим образом:

// this model will serve the composite component
@Named
@Scope("view")
public class MyCompositeComponentBean {
    private String firstComboValue, secondComboValue;
    private List<String> firstComboList, secondComboList;
    ...
}

Это пример страницы1.xhtml:

....
main department : <my:comboChainComponent /> <!-- 2 select items will be rendered here -->
secondary department : <my:comboChainComponent /> <!-- another 2 select items will be rendered here -->
....

И Page1Bean (Основной JSF Bean для Page1.xhtml)

@Named
@Scope("view")
public class Page1Bean {
    // inject the first bean for the composite component 1
    @Inject private MyCompositeComponentBean bean1;
    @Inject private MyCompositeComponentBean bean2;
    ...
}

Возможно ли достичь такого повторного использования?

Спасибо.

Ответ 1

Почему бы не использовать такой подход.

<mytag:combo id="combo1" 
         value="#{bean.firstData}" 
         model="#{globalBean.getList()}"
         update="form1:combo2"   />

<mytag:combo id="combo2" 
         value="#{bean.secondData}" 
         model="#{globalBean.getSubList(bean.firstData)}"  />

Вы можете использовать составной атрибут.

...
<composite:interface name="combo">
   ... define your attributes here
</composite:interface>

<composite:implementation>
<p:outputPanel id="content">
    <p:selectOneMenu id="select_menu_1" value="#{cc.attrs.value}">
         <f:selectItems value="#{cc.attrs.model}" />
        <p:ajax event="change" process="@this" update="#{cc.attrs.update}" />
    //add converter if you want 
    </p:selectOneMenu>
</p:outputPanel>
</composite:implementation>

Ответ 2

В зависимости от того, что вы пытаетесь реализовать, вы можете использовать какой-либо "компонент поддержки" (= класс java, связанный с вашим компонентным компонентом facelet). См. Это сообщение: http://weblogs.java.net/blog/cayhorstmann/archive/2010/01/30/composite-input-components-jsf

Возможно, в зависимости от того, что вы действительно делаете, вы, вероятно, можете лучше определить составные компоненты, в основном используя больше параметров и лучшую модель для передачи значений (при необходимости). Мне не хватает знаний о вашем приложении, чтобы дать лучший совет.

Ответ 4

Не уверен, что я прекрасно понимаю вас, но вы можете передать аргумент в состав составной компоненты.

    main department : <my:comboChainComponent worksOn="#{page1Bean.bean1}" /> <!-- 2 select items will be rendered here -->
secondary department : <my:comboChainComponent worksOn="#{page1Bean.bean2}"/> <!-- another 2 select items will be rendered here -->

Надеюсь, что это поможет...