Не могу установить выбранное значение ng-options
Я пытаюсь заполнить раскрывающийся список опций выбора и установить выбранное по умолчанию значение, используя ng-model и ng-options.
У меня есть следующий код на мой взгляд:
<select ng-model="thisTour.site" ng-options="site.name for site in siteList"></select>
И в моем контроллере:
$scope.siteList = [
{ id: 1, name: 'cycling'},
{ id: 2, name: 'walking'},
{ id: 3, name: 'holidays'}
]
$scope.thisTour.site = { id: 2, name: 'walking'};
Список заполняется правильными 3 вариантами из siteList
объект, но он не выбирает ходьбу по умолчанию, как я ожидал? Почему бы и нет?
Теперь, когда я изменю это:
$scope.thisTour.site = { id: 2, name: 'walking'};
К этому:
$scope.thisTour.site = $scope.siteList[1];
Теперь это работает. Зачем? Разве это не одно и то же?
4 ответа
Это потому, что angular ищет объектное равенство, чтобы связать его с вашим синтаксисом и вашим регистром $scope.siteList[1]
не равно { id: 2, name: 'walking'};
(2 объекта равны, только если они указывают на одну и ту же ссылку). Вы можете обойти это во многих отношениях, одним простым способом является использование track by
синтаксис с опциями ng для указания трека id
, что позволит отслеживать опции ng-option по указанному свойству связанного объекта, а не по самой ссылке на объект.
<select ng-model="thisTour.site"
ng-options="site.name for site in siteList track by site.id"></select>
Вы также можете использовать синтаксис для минимальной установки ng-модели, чтобы указать только идентификатор, используя select как часть в синтаксисе:-
Пример:-
ng-options="site.id as site.name for site in siteList"
и модель будет просто:-
$scope.thisTour.site = 2;
angular.module('app', []).controller('ctrl', function($scope){
$scope.thisTour = {};
$scope.siteList = [
{ id: 1, name: 'cycling'},
{ id: 2, name: 'walking'},
{ id: 3, name: 'holidays'}
]
$scope.thisTour.site = { id: 2, name: 'walking'};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<select ng-model="thisTour.site" ng-options="site.name for site in siteList track by site.id"></select>
{{thisTour.site}}
</div>
Из документации
trackexpr: - Используется при работе с массивом объектов. Результат этого выражения будет использоваться для идентификации объектов в массиве. Trackexpr, скорее всего, будет ссылаться на переменную значения (например, value.propertyName). При этом выбор сохраняется даже при воссоздании параметров (например, перезагрузка с сервера).
Также стоит отметить:
Не используйте select as и track by в одном выражении. Они не предназначены для совместной работы.
Это не то же самое, потому что объекты в JavaScript передаются по ссылке.
Если вы берете первый пример:
$scope.siteList = [
{ id: 1, name: 'cycling'},
{ id: 2, name: 'walking'},
{ id: 3, name: 'holidays'}
]
$scope.thisTour.site = { id: 2, name: 'walking'};
Затем вы делаете это:
$scope.thisTour.site.id = 3;
console.log($scope.siteList[1].id) // 2
Другими словами, хотя ваши два объекта имеют одинаковую стоимость, они не являются одним и тем же объектом. ngOptions
директива видит это, поэтому бы установить thisTour.site
пустое значение, потому что это не один из разрешенных вариантов.
Google "переходя по ссылке в javascript", чтобы узнать больше.
Так как вы используете весь объект в своем выборе, тогда, когда Angular сделает его сравнение, он увидит, совпадают ли объекты, чтобы установить ваш выбор. Я считаю, что есть способ изменить функциональность того, как Angular выполняет сравнения, но я просто перебираю select и делаю свои собственные сравнения, аналогичные приведенным ниже:
$scope.siteList = [
{ id: 1, name: 'cycling'},
{ id: 2, name: 'walking'},
{ id: 3, name: 'holidays'}
]
angular.forEach($scope.siteList, function(site, index) {
if (site.id == 2) {
$scope.thisTour.site = site;
}
});
Это установит фактический объект в вашу переменную, позволяя установить его в select.
Использование для директивы ng-init. То есть, когда выполняется инициализация, мы можем присвоить значение ng-модели.
<div ng-init="thisTour.site = siteList[position]">
<select ng-model="thisTour.site" ng-options="site.name for site in siteList track by site.id"></select>
</div>