Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 27c65fd

Browse files
committed
docs(select): explain track by for ngModelController
closes #2862, references #5238, references #3625, references #3012
1 parent ead4d02 commit 27c65fd

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

src/components/select/select.js

+46
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,52 @@ angular.module('material.components.select', [
7070
* </md-select>
7171
* </md-input-container>
7272
* </hljs>
73+
*
74+
* ## Selects and object equality
75+
* When using a `md-select` to pick from a list of objects, it is important to realize how javascript handles
76+
* equality. Consider the following example:
77+
* <hljs lang="js">
78+
* angular.controller('MyCtrl', function($scope) {
79+
* $scope.users = [
80+
* { id: 1, name: 'Bob' },
81+
* { id: 2, name: 'Alice' },
82+
* { id: 3, name: 'Steve' }
83+
* ];
84+
* $scope.selectedUser = { id: 1, name: 'Bob' };
85+
* });
86+
* </hljs>
87+
* <hljs lang="html">
88+
* <div ng-controller="MyCtrl">
89+
* <md-select ng-model="selectedUser">
90+
* <md-option ng-value="user" ng-repeat="user in users">{{ user.name }}</md-option>
91+
* </md-select>
92+
* </div>
93+
* </hljs>
94+
*
95+
* At first one might expect that the select should be populated with "Bob" as the selected user. However,
96+
* this is not true. To determine whether something is selected,
97+
* `ngModelController` is looking at whether `$scope.selectedUser == (any user in $scope.users);`;
98+
*
99+
* Javascript's `==` operator does not check for deep equality (ie. that all properties
100+
* on the object are the same), but instead whether the objects are *the same object in memory*.
101+
* In this case, we have two instances of identical objects, but they exist in memory as unique
102+
* entities. Because of this, the select will have no value populated for a selected user.
103+
*
104+
* To get around this, `ngModelController` provides a `track by` option that allows us to specify a different
105+
* expression which will be used for the equality operator. As such, we can update our `html` to
106+
* make use of this by specifying the `ng-model-options="{trackBy: '$value.id'}"` on the `md-select`
107+
* element. This converts our equality expression to be
108+
* `$scope.selectedUser.id == (any id in $scope.users.map(function(u) { return u.id; }));`
109+
* which results in Bob being selected as desired.
110+
*
111+
* Working HTML:
112+
* <hljs lang="html">
113+
* <div ng-controller="MyCtrl">
114+
* <md-select ng-model="selectedUser" ng-model-options="{trackBy: '$value.id'}">
115+
* <md-option ng-value="user" ng-repeat="user in users">{{ user.name }}</md-option>
116+
* </md-select>
117+
* </div>
118+
* </hljs>
73119
*/
74120
function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $compile, $parse) {
75121
return {

0 commit comments

Comments
 (0)