I have a array of objects that I\'m displaying using ng-options, and set ng-model with id. If i add track by
on it, the item can\'t selected, if not add, it wor
According to the documentation of ng-options (rephrased to your example).
This will work:
<select ng-model="country" ng-options="country.id as country.name for country in countryList track by country.id"></select>
$scope.country = $scope.countryList[0];
but this will not work:
<select ng-model="country" ng-options="country.id as country.name for country in countryList track by country.id"></select>
$scope.country = $scope.countryList[0].id;
In both examples, the track by expression is applied successfully to each country in the countryList array. Because the selected option has been set programmatically in the controller, the track by expression is also applied to the ngModel value. In the first example, the ngModel value is countryList[0] and the track by expression evaluates to countryList[0].id with no issue. In the second example, the ngModel value is countryList[0].id and the track by expression evaluates to countryList[0].id.id (which is undefined). As a result, the model value is not matched against any <option>
and the <select>
appears as having no selected value.
As explained in this github issue - "ng-options track by and select as are not compatible" and shown in this fiddle
"you just can't combine value as label for collection with track by. You have to pick the one or the other.".
For your case, the select should be:
<select ng-model="country" ng-options="country as country.name for country in countryList track by country.id"></select>
and in JS
$scope.country = $scope.countryList[0];
JSFiddle here for your case.
The value selected will be the object and not just the id alone.
Again the point is, you have to chose between select as label or the track by case.
This Is basically how track by
work. track by can only work with object not with any property of the object. and without track by it will work with a separate property not with entire object. Check the code part.
Some lines from Angular js track by (read it for better understanding)
This will work:
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select> $scope.selected = $scope.items[0];
but this will not work:
<select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select> $scope.selected = $scope.items[0].subItem;
angular.module('myApp', [])
.controller('MyController', ['$scope', function ($scope) {
$scope.countryList = [{id: 1, name: 'China'}, {id: 2, name: 'America'}, {id: 3, name: 'England'}]
$scope.country = {id: 1, name: 'China'};
$scope.countryID = 1;
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
<div class="container" ng-app="myApp">
<div ng-controller="MyController">
<p><select ng-model="country" ng-options="country as country.name for country in countryList"></select> no track by</p>{{country}}
<p><select ng-model="country" ng-options="country as country.name for country in countryList track by country.id"></select> have track by, can't selected by id</p>{{country}}
<p><select ng-model="countryID" ng-options="country.id as country.name for country in countryList"></select> no track by</p>{{countryID}}
<p><select ng-model="countryID" ng-options="country.id as country.name for country in countryList track by country.id"></select> have track by, can't selected by id</p>{{countryID}}
</div>
</div>
ng-model
behavior changes when you make use of track by
expression on ng-options
.
If you are using track by
then the value of model should be object but not simple ID. Check out working fiddle
Second case will work only if country is assigned as:
$scope.country = {
id: 3,
name: 'England'
};