ExtJS ComboBoxes – Part 1

ComboBoxes are one of the most popular components in any UI toolkit and the ExtJS combobox is no exception. However, the flexibility offered by a combobox comes at the expense of having to navigate through a minefield of configuration options. In the first article in this series I'll attempt to introduce some of the basics.

How Hard Can It Be?

At its heart a combobox is just a glorified textfield. To the right there is a little arrow known as a trigger. Typing in the field or clicking on the trigger causes a drop-down list of values to be shown. Selecting a value updates the text in the field.

Let's see just how simple a combobox can be when we strip away all of the optional configuration.

        Ext.create('Ext.form.field.ComboBox', {
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

That's it. Try it for yourself:

There are a few key features you should note for this very simple configuration:

  • You can type any value you like into the box, even if it isn't in the list.
  • Keyboard navigation of the list. Pressing the Down arrow key will display the list if it isn't already showing. The Up and Down arrow keys, Home and End can be used to move within the list. Enter can be used to select a value and Esc will close the list. Pressing Tab will select a value and jump to the next field.
  • The list of options is filtered as you type.
  • Clicking the trigger shows the full, unfiltered list of options.
  • The colour of the combobox changes when it has focus. Also notice how the trigger changes colour when the mouse moves over it. This attention to aesthetic details has been a significant factor in making ExtJS such a popular UI toolkit.
  • The list is normally shown below the field but if there's insufficient space it'll be shown above the field instead.

Disabling Typing

Setting editable to false will stop users being able to type in the combobox, forcing them to choose an option via the mouse or keyboard navigation instead.

        Ext.create('Ext.form.field.ComboBox', {
            editable: false,
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

There are a couple of knock-on effects with using this setting:

  • Clicking the body of the combobox now activates the drop-down list.
  • There is no way to display a filtered list of values; the list always shows all of the values.

This configuration makes sense when there are a small number of options and all of the possible values are known in advance. It is an alternative to using radio buttons. A combobox will usually take up less space on the screen but radio buttons allow the user to see the available options immediately, without needing to click on a trigger.

Forcing Selection

Whilst it may be tempting to set editable to false it isn't without its drawbacks. For a long list of values it can be difficult to find a value in the list. Allowing typing provides a quick and easy way to filter values based on the first few letters. In some cases the full list of values isn't even available and needs to be requested from a server as the user types.

In cases like these, setting forceSelection to true can prove to be a less restrictive alternative to using editable. It limits the user to picking one of the values in the list without disabling typing.

        Ext.create('Ext.form.field.ComboBox', {
            forceSelection: true,
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

Notice how you can type any value you like into the combobox but if you click away it'll revert back to the last valid value.

Hiding The Trigger

In cases where typing is enabled it can be desirable to hide the trigger. This is especially true for an 'auto-complete' style combobox.

        Ext.create('Ext.form.field.ComboBox', {
            hideTrigger: true,
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

Even though the trigger is no longer visible the list can still be activated by pressing the Down arrow key. It also shows when the user starts typing.

Type Ahead

Another option that works well for an 'auto-complete' combobox is typeAhead. As the user types, the text in the combobox is extended to match one of the values in the list. The extended text is automatically selected so that it will be replaced if the user continues to type.

        Ext.create('Ext.form.field.ComboBox', {
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'],
            typeAhead: true
        });
    

Trigger Action

By default, clicking the trigger will show all of the possible values in the drop-down list. Setting triggerAction to 'query' will cause the list to be filtered by the current text, just as it would if the list had been activated by the user typing.

        Ext.create('Ext.form.field.ComboBox', {
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'],
            triggerAction: 'query'
        });
    

Using the Down arrow key to display the drop-down menu is also affected.

The name query may seem a little counter-intuitive. It makes a lot more sense when you consider the case where the list of values is loaded remotely from a server. In that scenario the text is used to query the server for a list of suitable values. For a remote query there's actually no reason why the values listed need to start with the query text at all: it really can be thought of as a query rather than a filter.

Using this configuration with local data can actually be a little irritating. If you play with the example above for a few seconds you may well notice that once a value has been chosen, clicking the trigger just shows that value. This makes sense, it's the only value that matches the query filter, but making logical sense isn't always enough to pacify confused users. It needs to be intuitive. This can be remedied to some extent by adding in a few complementary options:

        Ext.create('Ext.form.field.ComboBox', {
            hideTrigger: true,
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'],
            triggerAction: 'query',
            typeAhead: true
        });
    

Granted, setting a triggerAction when the trigger is hidden may feel a little peculiar but keep in mind that the list can also be activated by pressing the Down arrow key. In this configuration the drop-down list is always consistent, showing filtered values no matter how the list is activated.

Labels

All ExtJS fields can have a label.

        Ext.create('Ext.form.field.ComboBox', {
            fieldLabel: 'Colour',
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

It's also possible to specify text to show in the combobox when it's empty. This takes up less space than a label but at the expense of the description only being visible when the field is empty.

        Ext.create('Ext.form.field.ComboBox', {
            emptyText: 'Colour',
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

Multiple Selections

ExtJS 4 introduced built-in support for multiple selections.

        Ext.create('Ext.form.field.ComboBox', {
            editable: false,
            multiSelect: true,
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

This demo also has typing disabled using editable: false. While this isn't strictly required it does make the user interaction much less confusing.

The delimiter setting can be used to specify the string used to separate the values on screen.

        Ext.create('Ext.form.field.ComboBox', {
            delimiter: ' OR ',
            editable: false,
            multiSelect: true,
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black']
        });
    

Setting The Initial Value

On the face of it, setting the initial value is fairly straightforward:

        Ext.create('Ext.form.field.ComboBox', {
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'],
            value: 'Blue'
        });
    

For some combobox configurations it makes sense to allow the initial value to be one that isn't in the list, like this:

        Ext.create('Ext.form.field.ComboBox', {
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'],
            value: 'White'
        });
    

For a multi-select combobox the value is an array of the selected items.

        Ext.create('Ext.form.field.ComboBox', {
            editable: false,
            multiSelect: true,
            store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'],
            value: ['Yellow', 'Black']
        });
    

As we'll see in part 3, it can prove a little more complicated to set an initial value for comboboxes that use more advanced configurations.