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