Skip to content
RomanPerin edited this page Sep 29, 2014 · 6 revisions

TOCSTART

TOCEND

The SelectOneMenu component is an extended version of the standard JSF SelectOneMenu component, which adds such features as auto-suggestion for convenient support of large lists, embedding components to select items and multi-column drop-down lists.


Online Demo

Key Features

Supporting all features of the standard SelectOneMenu component

OpenFaces <o:selectOneMenu> API-compatible with its standard analog <h:selectOneMenu>. You can migrate to the OpenFaces version quite easily. For example you have the following code:

    <h:selectOneMenu value="#{SelectOneMenuBean.selectedCity}"
                     converter="#{SelectOneMenuBean.cityConverter}">
        <f:selectItems value="#{SelectOneMenuBean.cityItems}"/>
    </h:selectOneMenu>

You just need to replace <h:selectOneMenu> to <o:selectOneMenu>

    <o:selectOneMenu value="#{SelectOneMenuBean.selectedCity}"
                     converter="#{SelectOneMenuBean.cityConverter}">
        <f:selectItems value="#{SelectOneMenuBean.cityItems}"/>
    </o:selectOneMenu>

After this you will be able to use all OpenFaces SelectOneMenu features. We still have one incompatibility between standard and OpenFaces realisation of this component - <f:selectItem> doesn't support the itemDisabled standard attribute, so you can't disable item for selection.
In the same way as in a standard <h:selectOneMenu> the value displayed in selected item doesn't always equal the value that will be submitted to server because it's just presentation value. In our component we actually make full html copy of SelectItem in suggestion list. So that means that all embedded components and styles from <f:selectItem> will be copied to selected item field after selection.

Specifying List of Items

To add the SelectOneMenu component to a page, use the <o:selectOneMenu> tag. There are three ways to specify items that will be displayed in the drop-down list. Regardless of the way you choose, each item is assigned a value which is an arbitrary Object that becomes a selected value of the SelectOneMenu component once an appropriate item is selected. You can specify SelectOneMenu list items in the following ways:

  • Create a fixed list of values right on the JSF page. To do so, you should use the <f:selectItem> tag to specify each separate item. The value attribute of the <f:selectItem> tag can either be a String literal, which specifies a string value for this item, or a value binding expression, which refers to an Object that will be the value for this item. The example below shows the SelectOneMenu component containing three items in the list.
        <f:selectItem value="Martin Luther King, Jr."/>
        <f:selectItem value="Inauguration Day"/>
        <f:selectItem value="Presidents Day"/>
    

It is also possible to add child components to the <f:selectItem> tag. The following example demonstrates this feature displaying not just name of the holiday, but also some icon which represent this holiday.

<f:selectItem value="New Year's Day">
    <h:graphicImage url="../images/selectonemenu/newyear.png"/>
    <h:outputText value="New Year's Day" />
</f:selectItem>
<f:selectItem value="Martin Luther King">
    <h:graphicImage url="../images/selectonemenu/luterday.png"/>
    <h:outputText value="Martin Luther King" style="padding-left: 5px;"/>
</f:selectItem>
<f:selectItem value="Inauguration Day">
    <h:graphicImage url="../images/selectonemenu/inaguration.png"/>
    <h:outputText value="Inauguration Day" style="padding-left: 5px;"/>
</f:selectItem>

When we embed some component into <f:selectItem> tag, the value attribute doesn't display anymore, so to display some text information we need to use <h:outputText> tag. But we still need to specify value attribute in <f:selectItem> tag, this value will be used for suggestions and also it will be submitted to server if the item is selected.

  • Retrieve the list of items from a backing bean. To do so, you should use the <f:selectItems/> tag, see JavaServer Faces specification for more information. The value attribute of the <f:selectItems/> tag should be bound to the collection or array of item value objects:
    <f:selectItems value="#{SelectOneMenuBean.availableItems}"/>
    
        <p>And here's how the <cite>SelectItems</cite> property is defined in the <tt>SelectOneMenuBean</tt> class:</p>
    
    public List getAvailableItems() {
        List itemValues = Arrays.asList(new String[]{"1 star",
                                        "2 stars", "3 stars"});
        return itemValues;
    }
    
        <p>Another more specific way to specify list of value is using of <tt>javax.faces.model.SelectItem:</tt></p>
    
    public List<SelectItem> getSelectItemsList() {
      List<SelectItem> selectItemsList = new ArrayList<SelectItem>();
      selectItemsList.add(new SelectItem(2, "Two Stars Hotel"));
      selectItemsList.add(new SelectItem(3, "Three Stars Hotel"));
      selectItemsList.add(new SelectItem(4, "Four Stars Hotel"));
      selectItemsList.add(new SelectItem(5, "Five Stars Hotel"));
      return selectItemsList;
    }
    ...
    <o:selectOneMenu value="#{SelectOneMenuBean.selectedHotelStars}">
      <f:selectItems var="any" value="#{SelectOneMenuBean.itemsList}"/>
    </o:selectOneMenu>
    
        <p>In the example above we will have <cite>SelectOneMenu</cite> with string values in the list, but when we
            select some value it will submit integer value to the server. See JavaServer Faces specification for
            more information about <tt>javax.faces.model.SelectItem</tt>.</p></li>
    <li>Combine the two aforementioned approaches by specifying the <u>&lt;f:selectItem&gt;</u> and <u>&lt;f:selectItems&gt;</u>
        tags in any order you need, like in following example:
    
     <f:selectItem value="Any value">
     <f:selectItems value="#{SelectOneMenuBean.availableItems}"/>
    
        <p>Like any JSF <cite>UIInput</cite> component, the <cite>SelectOneMenu</cite> component supports the standard <b>validator</b>, <b>required</b>,
            <b>converter</b>, <b>immediate</b> and <b>disabled</b> attributes. For more information about them, see
            JavaServer Faces specification (section "EditableValueHolder").</p></li>
    

Specifying Child Components

It was already mentioned that it is possible to specify any child components within the SelectItem component. However, SelectItem components are used only when you have a fixed number of items. For a dynamic or big set of items, it is more suitable to use the SelectItems component, which cannot include child components. However, if you need to specify a set of components that should be rendered inside of all items, you can specify these components as children of the <o:selectOneMenu> tag.

Child components of the <o:selectOneMenu> tag are used to render each drop-down item. Note that the same child components of the SelectOneMenu are rendered in every drop-down item. So in order for these components to display different data for each respective item, you should use a request-scope variable referring to the current item value object. The item value object is an object that you specify in the corresponding <o:selectOneMenu> tag or an entry in the <f:selectItems> collection or array. The name of this variable should be specified using the var attribute of the <o:selectOneMenu> tag.

The following example shows the SelectOneMenu component specified using child components:

<o:selectOneMenu value="#{SelectOneMenuBean.selectedBGColor}"
                 var="color"
  <f:selectItems value="#{SelectOneMenuBean.colors}"/>

  <h:outputText styleClass="color" style="background: #{color.name};"/>
  <h:outputText value="#{color.name}"/>
</o:selectOneMenuBean>

It is also possible to use child components of the SelectOneMenu component with the SelectItem components. The values of the SelectItem components are available using a request-scope variable specified in the var attribute of the <o:selectOneMenu> tag.

Here is an example of specifying child components of the SelectOneMenu component with the <f:selectItem> tags:

<o:selectOneMenu value="#{SelectOneMenuBean.selectedFont}"
                 var="size">
  <f:selectItem value="9pt"/>
  <f:selectItem value="10pt"/>
  <f:selectItem value="12pt"/>
  <f:selectItem value="14pt"/>
  <f:selectItem value="16pt"/>
  <f:selectItem value="18pt"/>
  <f:selectItem value="20pt"/>
  <h:outputText value="#{size}" style="font-size: #{size};"/>
</o:selectOneMenu>

Note that if you specified child components both for <f:selectItem> and <o:selectOneMenu>, the components specified in the <f:selectItem> tag take priority over the components specified for all items, and only the children of the respective <f:selectItem> tag are displayed for such items.

Presentation Column

As it was described above, after selecting any item in a list all it's content copied to selected item field. It can cause some problems, when you are using multi column displaying and do not want to copy all columns to selected item field. To solve this issue you can use itemPresentationColumn attribute. You need to specify number of column(default value -1) which will represent your selection in selected item field:

<o:selectOneMenu value="#{SelectOneMenuBean.selectedBGColor}"
                 var="color" itemPresentationColumn="1">
    <f:selectItems value="#{SelectOneMenuBean.colors}"/>
    <o:column width="12px">
        <h:outputText styleClass="color"
                      style="background: #{color.name};"/>
    </o:column>
    <o:column>
        <h:outputText value="#{color.name}"/>
    </o:column>
</o:selectOneMenu>

In this example we use itemPresentationColumn attribute to specify that we want to display only color name value in selected value field. Below you can see results of using tag with itemPresentationColumn attribute and without it.

Auto-Suggestion

The SelectOneMenu component can be configured to display a list of suggestions based on the input entered partially by the user. When this feature is turned on, the list of suggestions is updated on-the-fly as the user types text, and the user can select one of the provided suggestions any time when appropriate. This feature makes it easier to find items by typing only part of their text. You can turn on the auto-suggestion feature with the suggestionMode attribute. By default, this attribute is set to "all".

The SelectOneMenu component supports different auto-suggestion modes, each of which can be specified using one of the following values:

  • "stringStart" - Shows suggestions that begin with the entered value (works on the client side.)
  • "substring" - Shows suggestions that contain the entered value (works on the client side.)
  • "stringEnd" - Shows suggestions that end with the entered value (works on the client side.)
  • "all" - Shows all drop-down items in the list of suggestions (works on the client side.)
  • "custom" - Sends an Ajax request when the user is entering a value and returns a list of suggestions from the server (works on the server side using Ajax.)

The first four auto-suggestion modes work on client side and can be used to introduce the most robust suggestion functionality because no server round-trips are required in this case. However, this way is not efficient in case of large lists, because all of the suggestions must be preloaded on the client in these modes. To avoid resource-intensive preloading as well as to implement more flexible auto-suggestion scenarios, you can take advantage of the "custom" suggestion mode.

When you use the "custom" suggestion mode, the value attribute of the SelectItems components should be bound to the method that returns the list of suggestions corresponding to the entered string. You can get the entered value from the SelectOneMenu component using the "searchString" request-scope variable. To retrieve a variable by its name, you can use the org.openfaces.util.Faces.var(String varName) method. Note that the "searchString" variable can have a null value. The null value is passed when requesting the default suggestion items that should be shown by manual opening the SelectOneMenu without typing any text.

The example below shows usage of the "custom" auto-suggestion mode:

<o:selectOneMenu value="#{SelectOneMenuBean.city}"
                 suggestionMode="custom">
  <f:selectItems value="#{SelectOneMenuBean.cities}"/>
</o:selectOneMenu>

Here is how the above example can be implemented in the backing bean:

public List getCities() {
  String searchString = Faces.var("searchString", String.class);
  List filteredCities = searchString == null
    ? myCitiesDB.getDefaultCities()
    : myCitiesDB.findCitiesStartingWithText(searchString);
  return filteredCities;
}


You can set a delay that should elapse after the last key press before starting auto-suggestion and auto-completion. The time period for this delay should be specified for the suggestionDelay attribute in milliseconds (by default, "350"). This attribute is particularly useful when it's necessary to avoid too many Ajax requests that are sent to the server while the user is typing text. With the suggestionDelay attribute, you send only one Ajax request when the user has stopped typing.

Here's an example of using the suggestionDelay attribute:

<o:selectOneMenu value="#{SelectOneMenuBean.selectedBGColor}"
                 var="color"
                 suggestionMode="custom"
                 suggestionDelay="200"
...
</o:selectOneMenu>
When you are using client side auto suggestion of SelectOneMenu, it's important to remember that filtering will not be applied on outputted values, but it will be applied on the values which actually set to the value attribute of f:selectItem. If you are using non-string value for selectItem, filtering will be applied on toString() method of object or on the getAsString() method of jsf converter if you specified it.
You can fully remove suggestions from component, by setting suggestioMode attribute to none. It also
fully remove input field which show on element double click.

Keyboard Navigation

The SelectOneMenu component supports keyboard navigation. The user can open a drop-down list by using the Down Arrow key. After opening a drop-down list, the user can navigate between drop-down items with the Up Arrow, Down Arrow, Home, End, Page Up, Page Down keys and then select an item with the Enter key. To close the list without changing the value, the user can press the Esc key.

Customizing Appearance

You can set an image for the drop-down button by using the buttonImageUrl attribute. The buttonAlignment attribute lets you specify whether the drop-down button is positioned to the right or to the left of the component. This attribute can take the "right" or "left" values only. The default location of the button is to the right of the input field.

In the example below, the drop-down button is left-aligned:

<o:selectOneMenu buttonAlignment="left"/>

In most cases, the width of the drop-down list is the same as the width of the SelectOneMenu component itself. However, if the content of the list is too wide to fit in the SelectOneMenu, the width of the drop-down list can exceed the width of the component. In this case, you can specify alignment of the drop-down list with the listAlignment attribute by setting its value to "left" (default) or "right". The default left alignment means that the left edge of the drop-down list is aligned with the left edge of the SelectOneMenu component.

The following example shows the SelectOneMenu component with a right-aligned drop-down list.

<o:selectOneMenu listAlignment="right">
...
</o:selectOneMenu>

You can specify the maximum height and width of the drop-down list using the height and width properties of the listStyle attribute. If the number of drop-down items is too large to fit in the height of the drop-down list, a scroll is added.

Like the HTML <input> tag, <o:selectOneMenu> supports the title, tabindex and accesskey attributes. These attributes are rendered for a nested input field of the SelectOneMenu component.

Customizing Styles

You can apply styles for any part of the SelectOneMenu component, both when it's in the normal and rollover states. The table below lists all style attributes:

Part of component Style attributes Class attributes Rollover style attributes Rollover class attributes Focused style attributes Focused class attributes
Entire SelectOneMenu component style styleClass rolloverStyle rolloverClass focusedStyle focusedClass
Input field fieldStyle fieldClass rolloverFieldStyle rolloverFieldClass - -
Drop-down button buttonStyle buttonClass rolloverButtonStyle rolloverButtonClass - -
Pressed drop-down button pressedButtonStyle pressedButtonClass - - - -
Drop-down list listStyle listClass rolloverListStyle rolloverListClass - -
List item listItemStyle listItemClass rolloverListItemStyle rolloverListItemClass - -
Odd list item, if different from listItemStyle oddListItemStyle oddListItemClass - - - -
Header row in a multi-column drop-down list
listHeaderRowStyle listHeaderRowClass - - - -
Footer row in a multi-column drop-down list listFooterRowStyle listFooterRowClass - - - -

This example shows usage of one class attribute and two style attributes for the SelectOneMenu component.

.redBackground {
    background-color: red;
}
...
<o:selectOneMenu style="border-style: solid; border-width: 1px;
                        border-color: silver;"
                 listClass="redBackground"
                 rolloverButtonStyle="background-color: #ECECEC;">
    <f:selectItems value="#{SelectOneMenuBean.selectItems}"/>
</o:selectOneMenu>

When you need to customize styles for grid lines in a multi-column drop-down list, use the following attributes:

Horizontal lines in the drop-down list horizontalGridLines
Vertical lines in the drop-down list verticalGridLines
A line that separates the header from drop-down items headerHorizSeparator
Vertical lines between column headers headerVertSeparator
A line that separates the footer from drop-down items footerHorizSeparator
Vertical lines between column footers footerVertSeparator
All style attributes for a multi-column drop-down list should be specified as the CSS "border" property but without the prefix "border:".

Here's an example of applying styles to the grid lines of the drop-down list:

<o:selectOneMenu value="#{SelectOneMenuBean.selectedColor}"
    horizontalGridLines="1px dotted gray"
    verticalGridLines="1px dotted gray"
    headerHorizSeparator="3px solid gray"
    headerVertSeparator="1px solid gray"
    footerHorizSeparator="3px solid gray"
    footerVertSeparator="1px solid gray">
  ...
</o:selectOneMenu>

Client-Side Events

The SelectOneMenu component supports the following standard client-side events: onchange, onkeypress, onclick, ondblclick, oncontextmenu, onmousedown, onmouseover, onmouseup, onmouseout, onmousemove, onfocus, onblur, onkeydown, onkeyup.

Please note that the mouse events work for the entire SelectOneMenu component except for the drop-down list, while the keyboard events also work for the drop-down list.

In addition, the SelectOneMenu component provides two specific events:

Event name Description
ondropdown Occurs when the drop-down list is opened.
oncloseup Occurs when the drop-down list is closed.

Note that when registering events on client-side (e.g. with JavaScript), there are some exceptions to the standard way of adding events for the onchange, and onkeypress events. To assign handlers for these events on client-side, you should assign the onchange_adapted and onkeypress_adapted fields of the component instance instead of the onchange and onkeypress ones. This exception is only applicable when assigning event handlers dynamically on client-side, and you can use the event attributes mentioned above as usual if you're specifying them on server-side (e.g. in the xhtml file).

Server-Side Event Listeners

Given that the SelectOneMenu component is a UIInput component, it can fire javax.faces.event.ValueChangeEvent just like any other UIInput component does. To handle a value change event on the server side, the valueChangeListener attribute should be used in the same way as for the HTMLInputText component. You can also add a value change listener to the component by using the <f:valueChangeListener> tag.

Client-Side API

All client-side API methods for the SelectOneMenu component are listed below:

Method Description
getValue() Gets the value from the SelectOneMenu component on which this method is invoked.
setValue (value) Sets the value for the SelectOneMenu component on which this method is invoked.
dropDown() Opens the drop-down list for the SelectOneMenu component on which this method is invoked.
closeUp() Closes the drop-down list for the SelectOneMenu component on which this method is invoked.
isOpened() Returns "true" if the drop-down list is opened.
getDisabled() Returns a boolean value that specifies whether this component is disabled.
setDisabled(disabled) Specifies whether the component should be in a disabled state.
focus() Gives the keyboard focus to the SelectOneMenu component on which this method is invoked.

Difference between SelectOneMenu and DropDownField

Although the SelectOneMenu looks very much like the DropDownField component, they have one key difference besides some API differences described above. The DropDownField component (as well as its cousin SuggestionField) is essentially an input component, like other standard input components such as <h:inputText>. In other words, despite it contains the drop-down list to choose items from, the purpose of the DropDownField component is just the entry of text, and the component's drop-down list as well as the autocompletion functionality just assists the text entry. This particularly means that if for example the drop-down list contains two items with the same name (say London, UK and London, OH), it won't be possible to distinguish between them - the DropDownField will just contain the "London" text when clicking on any of these items and it will be the same as if the user entered this text without even opening the drop-down list.
In contrast, the SelectOneMenu component is a select component, which means that although it allows typing item name in its embedded input field, its purpose is to select from a predefined list of items. So typing "London" (or a partial text) will open a drop-down list for selecting the desired option, and the selected item will be saved in the component and will properly reflect the original item object that corresponds to the selected item.

Clone this wiki locally