15

我正在尝试填充下拉选择选项列表并使用 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'};

该列表正在填充siteList对象中正确的 3 个选项,但它没有像我期望的那样默认选择步行?为什么不?

现在,当我改变这个时:

$scope.thisTour.site = { id: 2, name: 'walking'};

对此:

$scope.thisTour.site = $scope.siteList[1];

现在它起作用了。为什么?不是一样的吗?

4

4 回答 4

46

那是因为 Angular 寻找对象相等性以将其与您的语法绑定,并且在您的情况下$scope.siteList[1]不等于{ id: 2, name: 'walking'};(只有当它们指向相同的引用时,2 个对象才相等)。您可以通过多种方式解决此问题,一种简单的方法是使用track by带有 ng-options 的语法来指定 track by id,这将使 ng-option 的选项能够通过绑定对象的指定属性而不是对象引用本身来跟踪。

<select ng-model="thisTour.site" 
    ng-options="site.name for site in siteList track by site.id"></select>

您还可以使用语法来最低限度地设置 ng-model 以仅使用select 作为语法的一部分指定 id :-

例子:-

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 变量(例如 value.propertyName)。有了这个选项,即使重新创建选项(例如从服务器重新加载),也会保留选择。

另外值得注意的是:

不要在同一个表达式中使用 select as 和 track by。它们并非旨在协同工作。

于 2014-12-16T21:35:19.410 回答
3

这不是一回事,因为 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

换句话说,虽然你的两个对象在value上是相等的,但它们不是同一个对象。该ngOptions指令看到这一点,因此将设置thisTour.site为空白值,因为它不是允许的选项之一。

谷歌“在 javascript 中通过引用传递”以了解更多信息。

于 2014-12-16T21:37:08.850 回答
1

由于您在选择中使用了整个对象,因此当 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;
    }
});

这会将实际对象设置为您的变量,允许在选择中设置它。

于 2014-12-16T21:36:40.427 回答
0

使用 ng-init 指令。这是一次执行的初始指令,我们可以为 ng-model 赋值。

<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>
于 2016-08-03T13:39:18.120 回答