Improve this Doc View Source

HTML `SELECT` element with angular data-binding.

# `ngOptions`

The `ngOptions` attribute can be used to dynamically generate a list of `<option>` elements for the `<select>` element using the array or object obtained by evaluating the `ngOptions` comprehension_expression.

In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a similar result. However, the `ngOptions` provides some benefits such as reducing memory and increasing speed by not creating a new scope for each repeated instance, as well as providing more flexibility in how the `select`'s model is assigned via `select as`. `ngOptions` should be used when the `select` model needs to be bound to a non-string value. This is because an option element can only be bound to string values at present.

When an item in the `<select>` menu is selected, the array element or object property represented by the selected option will be bound to the model identified by the `ngModel` directive.

Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can be nested into the `<select>` element. This element will then represent the `null` or "not selected" option. See example below for demonstration.

Note: `ngModel` compares by reference, not value. This is important when binding to an array of objects. See an example in this jsfiddle.

## `select as`

Using `select as` will bind the result of the `select as` expression to the model, but the value of the `<select>` and `<option>` html elements will be either the index (for array data sources) or property name (for object data sources) of the value within the collection. If a `track by` expression is used, the result of that expression will be set as the value of the `option` and `select` elements.

### `select as` with `trackexpr`

Using `select as` together with `trackexpr` is not recommended. Reasoning:

- Example: <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"> values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItem'}}], $scope.selected = {name: 'aSubItem'};
- track by is always applied to `value`, with the purpose of preserving the selection, (to `item` in this case)
- to calculate whether an item is selected we do the following:
  1. apply `track by` to the values in the array, e.g. In the example: [1,2]
  2. apply `track by` to the already selected value in `ngModel`: In the example: this is not possible, as `track by` refers to `item.id`, but the selected value from `ngModel` is `{name: aSubItem}`.

## Directive Info

- This directive executes at priority level 0.

## Usage

- as element:

      <select
        ng-model=""
        [name=""]
        [required=""]
        [ng-required=""]
        [ng-options=""]>
      ...
      </select>

### Arguments

Param | Type | Details
--- | --- | ---
ngModel | string | Assignable angular expression to data-bind to.
name (optional) | string | Property name of the form under which the control is published.
required (optional) | string | The control is considered valid only if value is entered.
ngRequired (optional) | string | Adds `required` attribute and `required` validation constraint to the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of `required` when you want to data-bind to the `required` attribute.

ngOptions
(optional)

comprehension_expression

in one of the following forms:

- for array data sources:
  - `label` `for` `value` `in` `array`
  - `select` `as` `label` `for` `value` `in` `array`
  - `label` `group by` `group` `for` `value` `in` `array`
  - `select` `as` `label` `group by` `group` `for` `value` `in` `array` `track by` `trackexpr`
- for object data sources:
  - `label` `for (``key` `,` `value``) in` `object`
  - `select` `as` `label` `for (``key` `,` `value``) in` `object`
  - `label` `group by` `group` `for (``key``,` `value``) in` `object`
  - `select` `as` `label` `group by` `group` `for` `(``key``,` `value``) in` `object`

Where:

- `array` / `object`: an expression which evaluates to an array / object to iterate over.
- `value`: local variable which will refer to each item in the `array` or each property value of `object` during iteration.
- `key`: local variable which will refer to a property name in `object` during iteration.
- `label`: The result of this expression will be the label for `<option>` element. The `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
- `select`: The result of this expression will be bound to the model of the parent `<select>` element. If not specified, `select` expression will default to `value`.
- `group`: The result of this expression will be used to group options using the `<optgroup>` DOM element.
- `trackexpr`: Used when working with an array of objects. The result of this expression will be used to identify the objects in the array. The `trackexpr` will most likely refer to the `value` variable (e.g. `value.propertyName`). With this the selection is preserved even when the options are recreated (e.g. reloaded from the server).

## Example

Edit in Plunker

    <script>
    angular.module('selectExample', [])
      .controller('ExampleController', ['$scope', function($scope) {
        $scope.colors = [
          {name:'black', shade:'dark'},
          {name:'white', shade:'light'},
          {name:'red', shade:'dark'},
          {name:'blue', shade:'dark'},
          {name:'yellow', shade:'light'}
        ];
        $scope.myColor = $scope.colors[2]; // red
      }]);
    </script>
    <div ng-controller="ExampleController">
      <ul>
        <li ng-repeat="color in colors">
          Name: <input ng-model="color.name">
          [<a href ng-click="colors.splice($index, 1)">X</a>]
        </li>
        <li>
          [<a href ng-click="colors.push({})">add</a>]
        </li>
      </ul>
      <hr/>
      Color (null not allowed):
      <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>

      Color (null allowed):
      <span  class="nullable">
        <select ng-model="myColor" ng-options="color.name for color in colors">
          <option value="">-- choose color --</option>
        </select>
      </span><br/>

      Color grouped by shade:
      <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
      </select><br/>

      Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
      <hr/>
      Currently selected: {{ {selected_color:myColor} }}
      <div style="border:solid 1px black; height:20px"
           ng-style="{'background-color':myColor.name}">
      </div>
    </div>

    it('should check ng-options', function() {
      expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
      element.all(by.model('myColor')).first().click();
      element.all(by.css('select[ng-model="myColor"] option')).first().click();
      expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
      element(by.css('.nullable select[ng-model="myColor"]')).click();
      element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
      expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
    });