Невозможно установить выбранное значение 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];

Теперь он работает. Зачем? Разве это не одно и то же?

Ответ 1

Это потому, что angular ищет эквивалент объекта, чтобы связать его с вашим синтаксисом, а inyour case $scope.siteList[1] не равен { id: 2, name: 'walking'}; (2 объекта равны, только если они указывают на одну и ту же ссылку). Вы можете обойти это разными способами, одним простым способом является использование синтаксиса track by с ng-параметрами для указания трека на id, который позволит отслеживать параметры опций ng с помощью указанного свойства связанного объекта чем сама ссылка на объект.

<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>

Ответ 2

Это не одно и то же, потому что объекты в 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", чтобы узнать больше.

Ответ 3

Поскольку вы используете весь объект в своем выборе, тогда, когда Angular делает это сравнение, он увидит, одинаковы ли объекты, чтобы установить ваш выбор. Я считаю, что есть способ изменить функциональность в том, как Angular выполняет сравнения, но я просто просматриваю выбор и делаю свои собственные сравнения, подобные приведенным ниже:

$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;
    }
});

Это установит фактический объект в вашу переменную, позволяя его установить в выборе.

Ответ 4

Использовать в директиве 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>