Improve this Doc View Source

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, `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 the `select` `as` part of the comprehension expression. `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.

## Complex Models (objects or collections)

Note: By default, `ngModel` watches the model by reference, not value. This is important when binding any input directive to a model that is an object or a collection.

Since this is a common situation for `ngOptions` the directive additionally watches the model using `$watchCollection` when the select has the `multiple` attribute or when there is a `track by` clause in the options expression. This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection has not changed identity but only a property on the object or an item in the collection changes.

Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection if the model is an array). This means that changing a property deeper inside the object/collection that the first level will not trigger a re-rendering.

## `select` `as`

Using `select` `as` will bind the result of the `select` 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` and `track by`

Do not use `select` `as` and `track by` in the same expression. They are not designed to work together.

Consider the following example:

    <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"></select>

    $scope.values = [{
      id: 1,
      label: 'aLabel',
      subItem: { name: 'aSubItem' }
    }, {
      id: 2,
      label: 'bLabel',
      subItem: { name: 'bSubItem' }
    }];

    $scope.selected = { name: 'aSubItem' };

With the purpose of preserving the selection, the `track by` expression is always applied to the element of the data source (to `item` in this example). To calculate whether an element is selected, we do the following:

1. Apply `track by` to the elements in the array. 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'}`, so the `track by` expression is applied to a wrong object, the selected element can't be found, `<select>` is always reset to the "not selected" option.

## Directive Info

- This directive executes at priority level 0.

## Usage

- as attribute:

      <ANY
        ng-model="string"
        [name="string"]
        [required="string"]
        [ng-required="string"]
        [ng-options="comprehension_expression"]>
      ...
      </ANY>

### 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` `label` `disable when` `disable` `for` `value` `in` `array` `label` `group by` `group` `for` `value` `in` `array` `track by` `trackexpr` `label` `disable when` `disable` `for` `value` `in` `array` `track by` `trackexpr` `label` `for` `value` `in` `array` | orderBy:`orderexpr` `track by` `trackexpr` (for including a filter with `track by`) 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` `label` `disable when` `disable` `for (``key``,` `value``) in` `object` `select` `as` `label` `group by` `group` `for` `(``key``,` `value``) in` `object` `select` `as` `label` `disable when` `disable` `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. `disable`: The result of this expression will be used to disable the rendered `<option>` element. Return `true` to disable. `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', notAnOption: true},
          {name:'red', shade:'dark'},
          {name:'blue', shade:'dark', notAnOption: true},
          {name:'yellow', shade:'light', notAnOption: false}
        ];
        $scope.myColor = $scope.colors[2]; // red
      }]);
    </script>
    <div ng-controller="ExampleController">
      <ul>
        <li ng-repeat="color in colors">
          <label>Name: <input ng-model="color.name"></label>
          <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
          <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
        </li>
        <li>
          <button ng-click="colors.push({})">add</button>
        </li>
      </ul>
      <hr/>
      <label>Color (null not allowed):
        <select ng-model="myColor" ng-options="color.name for color in colors"></select>
      </label><br/>
      <label>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></label><br/>

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

      <label>Color grouped by shade, with some disabled:
        <select ng-model="myColor"
              ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
        </select>
      </label><br/>

      Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
      <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');
    });