How to conditionally render an f:selectItem tag?
Asked Answered
P

8

44

How can I specify a conditional rendering for an <f:selectItem> tag. I need to display <f:selectItem> options according to a specific user's status.

For example, I wanted something like:

<f:selectItem itemLabel="Yes! I need a girlfriend!"
             rendered="false(or some boolean condition)"
             itemValue="o1"/>
Phial answered 3/8, 2011 at 19:18 Comment(0)
P
71

The <f:selectItem> does not support the rendered attribute. Your closest bet is the itemDisabled attribute which still displays the item, but makes it unselectable. This is also supported in <f:selectItems>.

In case of <p:selectOneMenu> you can then just add some CSS to hide disabled items.

<p:selectOneMenu ... panelStyleClass="hideDisabled">
    <f:selectItem itemValue="1" itemLabel="one" />
    <f:selectItem itemValue="2" itemLabel="two" itemDisabled="#{some.condition}" />
    <f:selectItem itemValue="3" itemLabel="three" />
</p:selectOneMenu>
.ui-selectonemenu-panel.hideDisabled .ui-selectonemenu-item.ui-state-disabled {
    display: none;
}

In case of <h:selectOneMenu> you're more dependent on whether the webbrowser supports hiding the disabled options via CSS:

<h:selectOneMenu ... styleClass="hideDisabled">
    <f:selectItem itemValue="1" itemLabel="one" />
    <f:selectItem itemValue="2" itemLabel="two" itemDisabled="#{some.condition}" />
    <f:selectItem itemValue="3" itemLabel="three" />
</h:selectOneMenu>
select.hideDisabled option[disabled] {
    display: none;
}

The server side alternative is to bring in a JSTL <c:if> around the individual <f:selectItem> to contitionally add it to the view like this (make sure you're aware of how JSTL works in JSF: JSTL in JSF2 Facelets... makes sense?):

<f:selectItem itemValue="1" itemLabel="one" />
<c:if test="#{not some.condition}">
    <f:selectItem itemValue="2" itemLabel="two"  />
</c:if>
<f:selectItem itemValue="3" itemLabel="three" />

Or, you could simply dynamically populate a List<SelectItem> in the backing bean based on the calculated conditions and bind it with <f:selectItems>.

Palaeontology answered 3/8, 2011 at 19:35 Comment(7)
Yes rendered attribute is not supported by f:selectitem hence I raised this question. Btw c:if solved the issue nicely. ThanksPhial
You're welcome. It has however a caveat: it ain't going to work when it depends on the repeated variable of JSF repeater components like ui:repeat, h:dataTable, etc.Palaeontology
Another possible solution would be to use ` <ui:fragment rendered="#{condition}"> ... Whatever else ... </ui:fragment> ` This one has the advantage of being a true JSF component. Keep in mind that there's a bug with that on JSF 2.0, as mentioned in this post.Reachmedown
@Reachmedown I can confirm that the ui:fragment rendered attribute work in general, but not with a selectItem. (myfaces 2.1.10)Albright
As far as I can tell both the panelStyleClass and styleClass attributes are completely ignored on p:selectOneMenu in PrimeFaces 6.1 community edition, so the CSS targeting shown does not work (anymore, I assume it worked at some stage previously).Slave
smart solution from brilliant guy !Adonic
@WebelITAustralia-upvoter see my answer below. You need to pass through the class.Spermatic
B
6

The workaround I use is setting the itemDisabled attribute and using this CSS:

select option[disabled] { display: none; }

But it needs to be fixed properly in JSF.

Binturong answered 9/5, 2012 at 6:41 Comment(1)
Could you indicate more precisely how that should be specified in a .css file? I tried .ui-selectonemenu-list-item a:disabled but that didn't work.Indifferent
C
3

<c:if> for me is also not working if it depends on the repeated variable of a <c:forEach> component (on first build phase it works but using ajax and updating the collection of the for-each it fails, showing some items twice and others not)

this is really one big issue in JSF. Disabling is not always an option, and this way much more code is necessary in the bean to address such "easy" things.

Choosy answered 18/2, 2012 at 0:57 Comment(0)
E
2

You can wrap it into ui:fragment code:

<ui:fragment rendered="false(or some boolean condition)">
  <f:selectItem itemLabel="Yes! I need a girlfriend!" itemValue="o1"/>
</ui:fragment>

Then item will be rendered only when boolean codition is true.

Eider answered 27/2, 2015 at 11:39 Comment(1)
As far as I can tell this does not work with f:selectItem, it still renders (appears as a selectable option), at least within a p:selectOneMenu. I don't practice comment-less down-voting on stackoverflow, but I think you should double-check this claim.Slave
G
2

Building off of BalusC's answer, it's possible to do it without a backing bean list in newer versions of JSF (I'm using JSF 2.2):

<h:selectOneMenu id="Value" value="#{cc.attrs.value}">
    <f:selectItem itemLabel="#{cc.attrs.placeholder}" noSelectionOption="true">
        <f:passThroughAttribute
            rendered="#{not empty cc.attrs.placeholder}"
            name="hidden" value=""/>
    </f:selectItem>
    <f:selectItems value="#{empty cc.attrs.allLabel ? [] : [1]}"
        var="item"
        itemLabel="#{cc.attrs.allLabel}"
        itemValue="#{cc.attrs.allValue}"/>
    <f:selectItems value="#{cc.attrs.codeList}" var="code" itemLabel="#{code.codeDesc}" itemValue="#{code.userCode}"/>
</h:selectOneMenu>

I wrapped it in a composite component with some specific requirements. The part related to this question is using f:selectItems with a value of either [] or [1]. When your condition makes it use [] then it will be omitted entirely, and when it uses [1] then it puts in a single item with the values you want.

Guidry answered 6/3, 2018 at 15:18 Comment(0)
N
0

You can also hide it using JS (jQuery). On Primefaces:

$('.ui-selectoneradio .ui-state-disabled').closest('tr').hide();

This is for p:selectOneRadio. Note that if you update the component or a container of the component, you must re-run the code.

Naturism answered 10/6, 2021 at 9:34 Comment(0)
S
-1

For me the "cleanest" way is in 2019 using JSF 2.3 and in order to avoid mixing jsf/html with jstl to

  1. set itemDisabled="true" and
  2. a custom class using jsf/passthrough pt:class="hidden".
<f:selectItem itemValue="itsValue" itemLabel="example"
    itemDisabled="#{exampleBean.hideItem}" 
    pt:class="#{exampleBean.hideItem ? 'hidden' : ''}" />

Of cause you need then the CSS style

.hidden {
    display: none !important;
}

This has the advantage that there can be still disabled elements in your list.

Spermatic answered 20/3, 2019 at 13:37 Comment(1)
Why the negative voting 3 years later, did something change?Spermatic
C
-3

I solved my problem doing this

<p:selectOneRadio id="myId" value="#{myView.myProperty}">
   <h:panelGroup rendered="#{myView.showMyOption}">
      <f:selectItem itemLabel="My Option" itemValue="0"/>
   </h:panelGroup>
   <f:selectItem itemLabel="My Option 1" itemValue="1"/>
   <f:selectItem itemLabel="My Option 2" itemValue="2"/>
</p:selectOneRadio>
Cudlip answered 26/1, 2015 at 18:7 Comment(1)
This "works" for rendered="false", but not for rendered="true".Palaeontology

© 2022 - 2024 — McMap. All rights reserved.