Skip to content

Commit a995ee1

Browse files
ryanhart2gkalpak
authored andcommitted
docs(ngOptions): explain the caveats of using select as and track by together
Changes: * Modify warning message to indicate that `track by` can be used with `select as`, but subject to certain limitations. * Provide both a working and an non-working example. * Explain why the latter does not work. Closes angular#13007
1 parent 794d1c1 commit a995ee1

File tree

1 file changed

+26
-17
lines changed

1 file changed

+26
-17
lines changed

src/ng/directive/ngOptions.js

+26-17
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,13 @@ var ngOptionsMinErr = minErr('ngOptions');
6666
* ### `select` **`as`** and **`track by`**
6767
*
6868
* <div class="alert alert-warning">
69-
* Do not use `select` **`as`** and **`track by`** in the same expression. They are not designed to work together.
69+
* Be careful when using `select` **`as`** and **`track by`** in the same expression.
7070
* </div>
7171
*
72-
* Consider the following example:
73-
*
74-
* ```html
75-
* <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"></select>
76-
* ```
72+
* Given this array of items on the $scope:
7773
*
7874
* ```js
79-
* $scope.values = [{
75+
* $scope.items = [{
8076
* id: 1,
8177
* label: 'aLabel',
8278
* subItem: { name: 'aSubItem' }
@@ -85,20 +81,33 @@ var ngOptionsMinErr = minErr('ngOptions');
8581
* label: 'bLabel',
8682
* subItem: { name: 'bSubItem' }
8783
* }];
84+
* ```
8885
*
89-
* $scope.selected = { name: 'aSubItem' };
86+
* This will work:
87+
*
88+
* ```html
89+
* <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
9090
* ```
91+
* ```js
92+
* $scope.selected = $scope.items[0];
93+
* ```
94+
*
95+
* but this will not work:
9196
*
92-
* With the purpose of preserving the selection, the **`track by`** expression is always applied to the element
93-
* of the data source (to `item` in this example). To calculate whether an element is selected, we do the
94-
* following:
97+
* ```html
98+
* <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
99+
* ```
100+
* ```js
101+
* $scope.selected = $scope.items[0].subItem;
102+
* ```
95103
*
96-
* 1. Apply **`track by`** to the elements in the array. In the example: `[1, 2]`
97-
* 2. Apply **`track by`** to the already selected value in `ngModel`.
98-
* In the example: this is not possible as **`track by`** refers to `item.id`, but the selected
99-
* value from `ngModel` is `{name: 'aSubItem'}`, so the **`track by`** expression is applied to
100-
* a wrong object, the selected element can't be found, `<select>` is always reset to the "not
101-
* selected" option.
104+
* In both examples, the **`track by`** expression is applied successfully to each `item` in the
105+
* `items` array. Because the selected option has been set programmatically in the controller, the
106+
* **`track by`** expression is also applied to the `ngModel` value. In the first example, the
107+
* `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
108+
* no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
109+
* expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
110+
* is not matched against any `<option>` and the `<select>` appears as having no selected value.
102111
*
103112
*
104113
* @param {string} ngModel Assignable angular expression to data-bind to.

0 commit comments

Comments
 (0)