Skip to content

SuggestionField 2.x

AlexanderLitus edited this page Aug 12, 2014 · 5 revisions

TOCSTART

TOCEND

The SuggestionField component is an input component that shows a list of suggestions based on user input and completes user input right in the input field. It has a similar functionality to DropDownField, but unlike DropDownField it looks like a plain text field. You can create a multi-column drop-down list and embed JSF components into it.


Online Demo

Key Features

Specifying List of Items

To add the SuggestionField component to a page, use the <o:suggestionField> tag. In order for the input suggestion feature to work properly, you should specify a list of suggestion items. There are three ways of specifying suggestion items. Regardless of the way you choose, each item is assigned a value that becomes a value of the SuggestionField component once an appropriate item is selected. The item value can either be a String or an arbitrary Object. See the Entering Non-String Values section for details of setting up the SuggestionField component for selection from a list of Objects rather than Strings.

You can use the following ways to specify the list of suggestion items:

  • To create a fixed list of values right on the JSF page. To do so, you should use the <o:dropDownItem> tag to specify each separate item. The value attribute of the <o:dropDownItem> 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 SuggestionField component containing three items in the list.
<o:suggestionField>
  <o:dropDownItem value="Red"/>
  <o:dropDownItem value="Yellow"/>
  <o:dropDownItem value="Blue"/>
</o:suggestionField>


It is also possible to add child components to the <o:dropDownItem> tag. The following example demonstrates this feature using color definitions along with their names. Note that when a color is selected (for example, "Red"), the text field will display not the name of the color, but its hexadecimal value (#FF0000).

<o:suggestionField>
  <o:dropDownItem value="#FF0000" >
    <h:graphicImage url="/important.gif"/>
    <h:outputText value="Red"/>
  </o:dropDownItem>
  <o:dropDownItem value="#FFFF00">
    <h:outputText value="Yellow"/>
  </o:dropDownItem>
  <o:dropDownItem value="#0000FF">
    <h:outputText value="Blue"/>
  </o:dropDownItem>
</o:suggestionField>
  • Retrieve the list of items from a backing bean. To do so, you should use the <o:dropDownItems> tag. The value attribute of the <o:dropDownItems> tag should be bound to the collection or array of org.openfaces.component.input.DropDownItem instances or item value objects:
<o:suggestionField>
  <o:dropDownItems value="#{DropDownBackingBean.dropDownItems}"/>
</o:suggestionField>

Here's how the dropDownItems property is defined in the DropDownBackingBean class:

public List getDropDownItems() {
  List itemValues = Arrays.asList(new String[]{"Red", "Yellow", "Blue"});
  return itemValues;
}
  • Combine the two aforementioned approaches by specifying the <o:dropDownItem> and <o:dropDownItems> tags in any order you need.
    You can specify only non-null item value objects in any approach you use to specify suggestion list items.
        <p>A value of the <cite>SuggestionField</cite> component can be maintained using the <b>value</b> attribute of
            <u>&lt;o:dropDownItems&gt;</u> tag. The usage of this attribute is similar to that in standard JSF input
            components such as <u>&lt;h:inputText&gt;</u> or <u>&lt;h:selectOneMenu&gt;</u>. This attribute should be
            bound to either a String or an Object attribute depending on the type of item value objects. See the <a
                    href="#SuggestionField2.x-EnteringNonStringValues">Entering Non-String Values</a> section for
            details of entering non-string values in the <cite>SuggestionField</cite> component.<br>
            Here's an example of using the <b>value</b> attribute.</p>
    
        <div class="code panel" style="border-width: 1px;">
            <div class="codeContent panelContent">
    
    <o:suggestionField value="#{DropDownBackingBean.selectedColor}>
      <o:dropDownItem value="Red"/>
      <o:dropDownItem value="Yellow"/>
      <o:dropDownItem value="Blue"/>
    </o:suggestionField>
    
            </div>
        </div>
        <p>You can specify the prompt text for the <cite>SuggestionField</cite> component using the <b>promptText</b>
            attribute.<br>
            The prompt text is a label or short instruction placed inside the <cite>SuggestionField</cite> component.The
            specified text will be shown to the user while the value of the <cite>SuggestionField</cite> component is
            empty and disappear from the screen once user types something into the <cite>SuggestionField</cite> or it
            gets input focus.</p>
    
        <div class="code panel" style="border-width: 1px;">
            <div class="codeContent panelContent">
    
    <o:suggestionField value="#{DropDownBackingBean.selectedColor}" promptText="Select the color">
      <o:dropDownItem value="Red"/>
      <o:dropDownItem value="Yellow"/>
      <o:dropDownItem value="Blue"/>
    </o:suggestionField>
    
            </div>
        </div>
        <p>You can customize the styles of the prompt text by using the <b>promptTextStyle</b> and
            <b>promptTextClass</b> attributes.</p></li>
    

Like any JSF UIInput component, the SuggestionField component supports the standard validator, required, converter, immediate and disabled attributes. For more information about them, see JavaServer Faces specification (section "EditableValueHolder").
Note that if you want to reload SuggestionField component using RichFaces Ajax framework you will have to wrap SuggestionField component into any JSF container component and reload that container component. For example you can use the <h:panelGroup> tag as a container. There's no such restriction when using the OpenFaces Ajax features.

<h:panelGroup id="containerForSuggestionField">
    <o:suggestionField value="#{DropDownBackingBean.selectedColor}>
        <o:dropDownItem value="Red"/>
        <o:dropDownItem value="Yellow"/>
        <o:dropDownItem value="Blue"/>
    </o:suggestionField>
</h:panelGroup>

Restricting Input to List Items Only

The user can type in any value, not necessarily available in the suggestion list. In some cases, it may be required to restrict the input only to the values from the predefined list. The SuggestionField component provides this ability while also enabling you to use features like auto-suggestion and auto-completion and many others. This behavior can be triggered by setting the customValueAllowed attribute to "false". This attribute defines whether it is possible to specify only a value that exists in the list of suggestions ("false") or whether it is possible to enter any value ("true").

Entering Non-String Values

With the SuggestionField component, you can enter non-string values, too. For instance, you may need to select an object from a set of JavaBean objects read from the database. In this case, you will need to specify these non-string objects as suggestion item values (using <o:dropDownItem> or <o:dropDownItems> tags). In addition, the following requirements must be met:

  • The SuggestionField component's value attribute should be bound to a property having the type of objects you are selecting from.
  • A converter for the appropriate type of objects should be specified. It can either be specified using the SuggestionField component's converter attribute, or there should be an application-wide converter for this type. The converter is used for both converting a selected item for display in the field and converting the entered text value back to the appropriate object type.

Specifying Child Components

From the previous section, you already know that you can specify any child components within the DropDownItem component. However, DropDownItem 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 DropDownItems 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:suggestionField> tag.

Child components of the <o:suggestionField> tag are used to render each suggestion item. Note that the same child components of the SuggestionField are rendered in every suggestion 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:dropDownItem> tag or an entry in the <o:dropDownItems> collection or array. The name of this variable should be specified using the var attribute of the <o:suggestionField> tag.

In the example below, the SuggestionField component is specified using child components:

<o:suggestionField value="#{DropDownBean.selectedBGColor}"
                 var="color"
                 converter="#{DropDownBean.colorConverter}">
  <o:dropDownItems value="#{DropDownBean.colors}"/>

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

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

Here is an example of specifying child components of the SuggestionField component with the <o:dropDownItem> tags:

<o:suggestionField value="#{DropDownBean.selectedFont}"
                 var="size">
  <o:dropDownItem value="9pt"/>
  <o:dropDownItem value="10pt"/>
  <o:dropDownItem value="12pt"/>
  <o:dropDownItem value="14pt"/>
  <o:dropDownItem value="16pt"/>
  <o:dropDownItem value="18pt"/>
  <o:dropDownItem value="20pt"/>

<h:outputText value="#{size}" style="font-size: #{size};"/> </o:suggestionField>

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

Creating Multi-Column Suggestion List

The SuggestionField component lets you specify a suggestion list to be displayed in multiple columns. The list of columns is specified using the <o:column> tags within the <o:suggestionField> tag. Child components of the <o:column> tag are used to render each cell of the current item just like in the DataTable 2.x component. As in case of specifying child components described in the previous section, you should use a request-scope variable referring to the current item data in order for child components to display different data for each respective item.

You can specify the "header" and "footer" facets , styles and client-side events for the <o:column> tag. Also, the <o:column> tag has the width, align and valign attributes that are rendered onto the <col> tag of the respective column. In addition, it is possible to group several columns using the <o:columnGroup> tag and add additional group headers. For more details about the <o:column> and <o:columnGroup> tags, see the DataTable 2.x component documentation.

Here's an example of specifying a multi-column suggestion list in the SuggestionField component:

<o:suggestionField value="#{DropDownBean.selectedBGColor}"
                 var="color"
                 converter="#{DropDownBean.colorConverter}">
  <o:dropDownItems value="#{DropDownBean.colors}"/>
  <o:column width="12px">
    <h:outputText styleClass="colorRect" style="background: #{color.name};"/>
  </o:column>
  <o:column>
    <h:outputText value="#{color.name}"/>
  </o:column>
</o:suggestionField>

Auto-Suggestion

The SuggestionField component displays a list of suggestions based on the input entered partially by the user. 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 off the auto-suggestion feature with the suggestionMode attribute. By default, this attribute is set to "stringStart".

The SuggestionField 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 suggestion 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 DropDownItems 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 SuggestionField component using the "searchField" request-scope variable. To retrieve a variable by its name, you can use the org.openfaces.util.Faces.var(String varName) method.

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

<o:suggestionField value="#{DropDownBean.city}"
                 converter="#{DropDownBean.cityNameConverter}"
                 suggestionMode="custom">
  <o:dropDownItems value="#{DropDownBean.cities}"/>
</o:suggestionField>

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 = myCitiesDB.findCitiesStartingWithText(searchString);
  return filteredCities;
}


There are two attributes that control how auto-suggestion and auto-completion features are activated. The integer suggestionMinChars attribute specifies the minimum number of characters that should be typed for auto-completion and auto-suggestion features to be activated. By default, the suggestionMinChars attribute is set to "2".

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 suggestionMinChars and suggestionDelay attributes:

<o:suggestionField value="#{DropDownBean.selectedBGColor}"
                 var="color"
                 suggestionMode="custom"
                 suggestionDelay="200"
                 suggestionMinChars="3"
                 converter="#{DropDownBean.colorConverter}">
...
</o:suggestionField>

Partial Loading of Drop-Down List

When the user explicitly opens the component's drop-down list, the full list of unfiltered items is shown. By default, this whole list is preloaded to avoid additional requests and quickly show the drop-down list. In cases when there are too many items it is possible to customize how drop-down items are loaded. First, you should switch your SuggestionField to a "custom" auto-suggestion mode, as described in the previous section. The algorithm for loading custom suggestions is the same as described there with some additions, which are described below in this section.

It is possible to customize how much items are preloaded with the preloadedItemCount attribute. By default, it is equal to -1, which means that all items are preloaded, but you can change it to 0 or any positive number. Whenever preloadedItemCount is set to a non-default value, only a part of items is preloaded, and the rest of items are loaded on demand when the drop-down list is scrolled to the end, if more items are available. So the list is loaded in portions in this case. The number of rows in a portion can be controlled with the pageSize attribute, which can be set to -1 (a default value), or any positive number. The special value of -1 means that all of the remaining rows should be preloaded.

Note that unless pageSize is set to -1, it is needed to declare one more attribute for partial data loading to work: the totalItemCount attribute, which should be declared as a value binding expression that returns the total number of rows in the unfiltered list.

As it was already mentioned, the SuggestionField component should have the "custom" auto-suggestion mode for partial loading to work. Just like described in the previous section, the method which returns data for the SuggestionField component should use the "searchString" variable for looking up the records. In addition to this, it should also use the following two variables: "pageStart", and "pageSize". These are integer variables which specify the range of records in the result set which is currently being requested. This way only the portion that needs to be shown will have to be loaded from the database. Here's a modification of the getCities() method from the previous section, which is adapted for partial list loading:

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

The getAllCities() and findCitiesStartingWithText methods here are supposed to issue database queries which return a range of records starting from the record whose number is specified with the pageStart variable, and return the maximum of pageSize records.

Auto-Completion

The SuggestionField component provides the auto-completion feature which in addition to auto-suggestion can be used to simplify selection of a value among the items specified with the <o:dropDownItem> or <o:dropDownItems> tags. When auto-completion is turned on, the SuggestionField component completes partially entered text in the input field. The text is completed to the first suggestion item that starts with the typed text. The part added as a result of auto-completion is marked as selected.

The auto-completion feature can be turned on by setting the autoComplete attribute to "true". By default it is turned on. Auto-completion, like the auto-suggestion feature, also depends on the suggestionMinChars and suggestionDelay attributes, described in the previous section.

Below is an example of using the autoComplete attribute:

<o:suggestionField value="#{DropDownBean.selectedBGColor}"
                 var="color"
                 autoComplete="true"
                 suggestionDelay="200"
                 suggestionMinChars="3"
                 converter="#{DropDownBean.colorConverter}">
...
</o:suggestionField>

Keyboard Navigation

The SuggestionField component supports keyboard navigation. After opening a suggestion list, the user can navigate between suggestion 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.

By default, the suggestion list is opened only when the user starts typing in the field. You can change this behavior by setting the manualListOpeningAllowed attribute to "true". This attribute specifies whether a suggestion list can be opened using the Down Arrow key.

By default, the suggestion list in the SuggestionField component is hidden until the user starts typing (or presses the Down Arrow key). Once the list is opened, it remains visible until the user selects an item. To close the list without changing the value, the user can either press the Esc key or click anywhere outside of the component. However, in addition to the ability to close the suggestion list manually, you can specify a time period after which the list is closed automatically. To do so, set the time (in milliseconds) in the timeout attribute. The value of timeout equal to "-1" (default) means that the suggestion list should not be closed automatically.

Customizing Appearance

In most cases, the width of the suggestion list is the same as the width of the SuggestionField component itself. However, if the content of the list is too wide to fit in the SuggestionField, the width of the suggestion list can exceed the width of the component. In this case, you can specify alignment of the suggestion 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 suggestion list is aligned with the left edge of the SuggestionField component.

The following example shows the SuggestionField component with a right-aligned suggestion list.

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

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

Like the HTML <input> tag, <o:suggestionField> supports the title, tabindex, accesskey, maxlength and size attributes. Note that the maxlength attribute only affects the maximum number of characters that a user can type, but it is still possible to select any text from the drop-down list, no matter how long it is.

Customizing Styles

You can apply styles for any part of the SuggestionField 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 SuggestionField component style styleClass rolloverStyle rolloverClass focusedStyle focusedClass
Suggestion 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 suggestion list
listHeaderRowStyle listHeaderRowClass - - - -
Footer row in a multi-column suggestion list listFooterRowStyle listFooterRowClass - - - -

This example shows usage of one class attribute and one style attribute for the SuggestionField component.

.dropDownList {
   background-color: red;
   }
...
<o:suggestionField
        style="border-style: solid; border-width: 1px; border-color: silver;"
        listClass="dropDownList">
  <o:dropDownItems value="#{DropDownBackingBean.dropDownItems}"/>
</o:suggestionField>

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

Horizontal lines in the suggestion list horizontalGridLines
Vertical lines in the suggestion list verticalGridLines
A line that separates the header from suggestion items headerHorizSeparator
Vertical lines between column headers headerVertSeparator
A line that separates the footer from suggestion items footerHorizSeparator
Vertical lines between column footers footerVertSeparator
All style attributes for a multi-column suggestion 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 suggestion list:

<o:suggestionField value="#{DropDownBean.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:suggestionField>

Client-Side Events

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

Please note that the mouse events work for the entire SuggestionField component except for the suggestion list, while the keyboard events also work for the suggestion list. In addition, the SuggestionField component provides two specific events:

Event name Description
ondropdown Occurs when the suggestion list is opened.
oncloseup Occurs when the suggestion 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 SuggestionField 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 SuggestionField component are listed below:

Method Description
getValue() Gets the value from the SuggestionField component on which this method is invoked.
setValue (value) Sets the value for the SuggestionField on which this method is invoked.
dropDown() Opens the suggestion list for the SuggestionField component on which this method is invoked.
closeUp() Closes the suggestion list for the SuggestionField component on which this method is invoked.
isOpened() Returns "true" if the suggestion 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.