The options binding

The options binding controls what options should appear in a drop-down list (i.e., a <select> element) or multi-select list (e.g., <select size='6'>). This binding cannot be used with anything other than <select> elements.

The value you assign should be an array (or observable array). The <select> element will then display one item for each item in your array.

Tip

For a multi-select list, to set which of the options are selected, or to read which of the options are selected, use the selectedOptions binding. For a single-select list, you can also read and write the selected option using the value binding.

Examples

Drop-down list

<p>
  Destination country:
  <select data-bind="options: availableCountries"></select>
</p>
var viewModel = {
  // These are the initial options
  availableCountries: fw.observableArray(['France', 'Germany', 'Spain'])
};

// ... then later ...
viewModel.availableCountries.push('China'); // Adds another option

Multi-select list

<p>
  Choose some countries you would like to visit:
  <select data-bind="options: availableCountries" size="5" multiple="true"></select>
</p>
var viewModel = {
  availableCountries: fw.observableArray(['France', 'Germany', 'Spain'])
};

Drop-down list representing arbitrary JavaScript objects, not just strings

<p>
  Your country:
  <select data-bind="options: availableCountries,
                     optionsText: 'countryName',
                     value: selectedCountry,
                     optionsCaption: 'Choose...'"></select>
</p>

<div data-bind="visible: selectedCountry"> <!-- Appears when you select something -->
  You have chosen a country with population
  <span data-bind="text: selectedCountry() ? selectedCountry().countryPopulation : 'unknown'"></span>.
</div>
// Constructor for an object with two properties
var Country = function(name, population) {
  this.countryName = name;
  this.countryPopulation = population;
};

var viewModel = {
  availableCountries : fw.observableArray([
    new Country("UK", 65000000),
    new Country("USA", 320000000),
    new Country("Sweden", 29000000)
  ]),
  selectedCountry : fw.observable() // Nothing selected by default
};

Drop-down list representing arbitrary JavaScript objects, with displayed text computed as a function of the represented item

<!-- Same as previous example, except the <select> box expressed as follows: -->
<select data-bind="options: availableCountries,
                   optionsText: function(item) {
                     return item.countryName + ' (pop: ' + item.countryPopulation + ')'
                   },
                   value: selectedCountry,
                   optionsCaption: 'Choose...'"></select>

Parameters

  • Main parameter: You should supply an array (or observable array). For each item, Footwork will add an <option> to the associated <select> node. Any previous options will be removed.

    • If your parameter's value is an array of strings, you don't need to give any other parameters. The <select> element will display an option for each string value. However, if you want to let the user choose from an array of arbitrary JavaScript objects (not merely strings), then see the optionsText and optionsValue parameters below.

    • If this parameter is an observable value, the binding will update the element's available options whenever the value changes. If the parameter isn't observable, it will only set the element's available options once and will not update them again later.

  • Additional parameters

    • optionsCaption

      Sometimes, you might not want to select any particular option by default. But a single-select drop-down list usually starts with some item selected, so how can you avoid preselecting something? The usual solution is to prefix the list of options with a special dummy option that just reads "Select an item" or "Please choose an option" or similar, and have that one selected by default.

      This easy to do: just add an additional parameter with name optionsCaption, with its value being a string to display. For example:

      <select data-bind='options: myOptions,
                  optionsCaption: "Select an item...",
                           value: myChosenValue'></select>
      

      Footwork will prefix the list of items with one that displays the text "Select an item..." and has the value undefined. So, if myChosenValue holds the value undefined (which observables do by default), then the dummy option will be selected. If the optionsCaption parameter is an observable, then the text of the initial item will update as the observable's value changes.

    • optionsText

      See Example 3 above to see how you can bind options to an array of arbitrary JavaScript object - not just strings. In this case, you need to choose which of the objects' properties should be displayed as the text in the drop-down list or multi-select list. Example 3 shows how you can specify that property name by passing an additional parameter called optionsText.

      If you don't want to display just a simple property value as the text for each item in the dropdown, you can pass a JavaScript function for the optionsText option and supply your own arbitrary logic for computing the displayed text in terms of the represented object. See Example 4 above, which shows how you could generate the displayed text by concatenating together multiple property values.

    • optionsValue

      Similar to optionsText, you can also pass an additional parameter called optionsValue to specify which of the objects' properties should be used to set the value attribute on the <option> elements that Footwork generates. You can also specify a JavaScript function to determine this value. This function will receive the selected item as its only argument and should return a string to use for the <option> element's value attribute.

      Typically you'd only want to use optionsValue as a way of ensuring that Footwork can correctly retain selection when you update the set of available options. For example, if you're repeatedly getting a list of "car" objects via Ajax calls and want to ensure that the selected car is preserved, you might need to set optionsValue to "carId" or whatever unique identifier each "car" object has, otherwise Footwork won't necessarily know which of the previous "car" objects corresponds to which of the new ones.

    • optionsIncludeDestroyed

      Sometimes you may want to mark an array entry as deleted, but without actually losing record of its existence. This is known as a non-destructive delete. For details of how to do this, see the destroy function on observableArray.

      By default, the options binding will skip over (i.e., hide) any array entries that are marked as destroyed. If you want to show destroyed entries, then specify this additional parameter like:

      <select data-bind='options: myOptions,
         optionsIncludeDestroyed: true'></select>
      
    • optionsAfterRender

      If you need to run some further custom logic on the generated option elements, you can use the optionsAfterRender callback. See Note 2 below.

    • selectedOptions

      For a multi-select list, you can read and write the selection state using selectedOptions. Technically this is a separate binding, so it has its own documentation.

    • valueAllowUnset

      If you want Footwork to allow your model property to take values that have no corresponding entry in your <select> element (and display this by making the <select> element blank), then see documentation for valueAllowUnset.

Notes

Selection is preserved when setting/changing options

When the options binding changes the set of options in your <select> element, Footwork will leave the user's selection unchanged where possible. So, for a single-select drop-down list, the previously selected option value will still be selected, and for a multi-select list, all the previously selected option values will still be selected (unless, of course, you've removed one or more of those options).

That's because the options binding tries to be independent of the value binding (which controls selection for a single-select list) and the selectedOptions binding (which controls selection for a multi-select list).

Post-processing the generated options

If you need to run some further custom logic on the generated option elements, you can use the optionsAfterRender callback. The callback function is invoked each time an option element is inserted into the list, with the following parameters:

  1. The inserted option element

  2. The data item against which it is bound, or undefined for the caption element

Here's an example that uses optionsAfterRender to add a disable binding to each option.

<select size="3" data-bind="
  options: myItems,
  optionsText: 'name',
  optionsValue: 'id',
  optionsAfterRender: setOptionDisable">
</select>
var vm = {
  myItems: [
    { name: 'Item 1', id: 1, disable: fw.observable(false)},
    { name: 'Item 3', id: 3, disable: fw.observable(true)},
    { name: 'Item 4', id: 4, disable: fw.observable(false)}
  ],
  setOptionDisable: function(option, item) {
    fw.applyBindingsToNode(option, {disable: item.disable}, item);
  }
};

fw.applyBindings(vm);