1

I want to use a selectOneMenu to have a user choose a value. In some cases I want to disable one of the values shown in the menu. I tried using render on both the selectItems as well as selectOneMenu as well as added a ui:fragment around the Menu but I always get all the values from both lists shown. Any ideas how to prevent that? Here my current last try that again resulted in twice the list and the item in question once enabled and once disabled in it:

<ui:fragment rendered="#{cc.attrs.showP==true}">
    <h:selectOneMenu id="type" binding="#{cc.type}">
        <f:selectItems value="#{typeDAO.findAll()}"/>
    </h:selectOneMenu>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.showP==false}">
    <h:selectOneMenu id="type" binding="#{cc.type}">
        <f:selectItems value="#{typeDAO.findAll()}" var="item" itemDisabled="#{item=='P'}"/>
    </h:selectOneMenu>
</ui:fragment>
TomFree
  • 1,091
  • 3
  • 17
  • 31
  • Remove `==true` and `==false`, if `#{cc.attrs.showP}` is a boolean value then it will suffice. If this doesn't work display `#{cc.attrs.showP}` and check if it really is what you think. – Geinmachi Aug 08 '16 at 18:41
  • Wasn't the issue I only got one selectbox with duplicate number of options. Found the issue by now. see below. Thanks again – TomFree Aug 08 '16 at 18:48

2 Answers2

3

Your concrete problem is caused because you're binding physically multiple components to the same variable.

<h:selectOneMenu ... binding="#{cc.type}" />
<h:selectOneMenu ... binding="#{cc.type}" />

If the getter behind binding returns non-null, then JSF will use it instead of creating a new one. Basically, the second tag will reuse the component created in the first tag and set/add all attributes/items to it.

Your particular case can be solved in at least two ways:

  1. Use JSTL to build the JSF component tree conditionally instead of using JSF to render the HTML output conditionally. You shouldn't have physically multiple components in the JSF component tree sharing the same binding let alone the same id.

    <c:if test="#{cc.attrs.showP}">
        <h:selectOneMenu id="type" binding="#{cc.type}">
            ...
        </h:selectOneMenu>
    </c:if>
    <c:if test="#{not cc.attrs.showP}">
        <h:selectOneMenu id="type" binding="#{cc.type}">
            ...
        </h:selectOneMenu>
    </c:if>
    
  2. Make your code DRY. I.e. get rid of all code duplication.

    <h:selectOneMenu id="type" binding="#{cc.type}">
        <f:selectItems value="#{typeDAO.findAll()}" var="item" itemDisabled="#{not cc.attrs.showP and item eq 'P'}" />
    </h:selectOneMenu>
    

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • thanks Ballus. Very much like the second one. Somehow didn't really think of using logical operators in itemdisabled. Makes a lot of sense – TomFree Aug 09 '16 at 12:05
  • itemDisabled is not working at the f:selectItems. – Derzu May 19 '21 at 15:04
0

Guess I found it - bit weird to answer my question though. I think it's because the possible values of the menu are created before the rendered attributes are evaluated and since I did bind both menus to the same variable/id I got all items of the two menus. Thus I now used different names and then in my composite component have some logic that checks which one is used and continues to use the right value. Works :-)

Bit weird to me is this thing that as a developer u have to know when the attribute list is built in comparison to when the rendering happens. I recently had a similar issue with foreach and repeat. Is there any way to know these things as part of some overarching concept that I can remember or is that really case by case? Thanks guys!

TomFree
  • 1,091
  • 3
  • 17
  • 31