JSF-2 f:selectItems with Map does not display itemLabel

Alex Ormond picture Alex Ormond · May 18, 2012 · Viewed 29.8k times · Source

When I use f:selectItems to display items in a Map I cannot display the value of the Map item, only the key. f:selectItems does not use the itemLabel at all. When I use a List instead things work.

The following does make use of the itemLabel to display the "description" of an item in a List:

<h:selectOneMenu>
  <f:selectItems value="#{testBB.testList}" var="s"
    itemLabel="TEST #{s.description}" itemValue="#{TEST s.name}" />
</h:
selectOneMenu>

The following attempt to display the value of an item in a Map does not work. It displays the item's key, but not using the itemLabel attribute, as can be discerned by that lack of output of the "TEST" text.

<rich:select>
  <f:selectItems value="#{testBB.testMap}" var="s"
    itemLabel="TEST #{s.value}" itemValue="TEST #{s.key}" />
</rich:select>

The simple backing bean used follows:

public class TestBB {
  private Map<String, String> testMap;
  private List<TestItem> testList;

  public TestBB() {
    testMap = new HashMap<String, String>();
    testMap.put("1_key", "Item One");
    testMap.put("2_key", "Item Two");
    testMap.put("3_key", "Item Three");

    testList = new ArrayList<TestItem>();
    testList.add( new TestItem("name_1", "description_1") );
    testList.add( new TestItem("name_2", "description_2") );
    testList.add( new TestItem("name_3", "description_3") );
  }

  public Map<String, String> getTestMap() {
    return testMap;
  }

  public List<TestItem> getTestList() {
    return testList;
  }

}

So, any ideas on how to make this work, that is, how to effectively use a Map with selectItems?

Answer

BalusC picture BalusC · May 18, 2012

Your question is sound, but the code makes it confusing and ambiguous. I'll just ignore your code in this answer.

As to the concrete question "How to use Map in <f:selectItems>", you need to realize that map keys are by default been used as item labels and that map values are by default been used as item values. You seem to expect it to be the other way round (honestly, I'd intuitively also expect that, but that was just a design desicion --the map key forces uniqueness and option labels should in UI perspective definitely be unique, but option values does not necessarily need to be unique).

So, this should do (note that I use LinkedHashMap here as it maintains the insertion order):

map = new LinkedHashMap<String, String>();
map.put("Label 1", "value1");
map.put("Label 2", "value2");
map.put("Label 3", "value3");

with

<f:selectItems value="#{bean.map}" />

If you want so swap the keys and values, then you should be iterating over Map#entrySet(). This works only when your environment supports EL 2.2 as you have to invoke it by a direct method invocation as there's no getter for that.

E.g.

map = new LinkedHashMap<String, String>();
map.put("value1", "Label 1");
map.put("value2", "Label 2");
map.put("value3", "Label 3");

with

<f:selectItems value="#{bean.map.entrySet()}" var="entry" 
    itemValue="#{entry.key}" itemLabel="#{entry.value}" />

See also: