AngularJS选择框在型号变更时未更新

a1o7rhls  于 2022-11-28  发布在  Angular
关注(0)|答案(4)|浏览(123)

我有一个这样的控制器

app.controller("ReservationCtrl", function($scope) {

    $scope.rooms = [{id: 1, name: "Room 1"}, {id: 2, name: "Room 2", }];
    $scope.reservation = {id: 1, time: "9AM", room: {id: 2, name: "Room 2"}};

});

视图如下所示:

<select ng-model="reservation.room" ng-options="room as room.name for room in rooms"></select>

问题是选择框不会绑定到正确的房间,除非我说

$scope.reservation.room = $scope.rooms[1];

这对于开发是相当不方便的,因为房间并不是reservation模型上唯一需要绑定到选择框的字段。我如何才能在不做这一额外步骤的情况下应用绑定?
此外,如果我执行以下操作,绑定会再次断开

$http.get("/reservation/2").success(function(data) { $scope.reservation = angular.copy(data); });
v1l68za4

v1l68za41#

我想这是因为,
ng-options中如果选择一个选项,则所选值是一个对象

    • EX**:如果选择第一个选项,则模型值是$scope.rooms{id: 1, name: "Room 1"})中第一个元素的对象。

对象是引用类型的数据类型。所以它所做的是如果对象创建一次,那么它的所有使用都指向那个对象。看一下这个article
所以你选择的值是一个引用类型的对象。在你的例子中,你有两个独立的对象,分别是$scope.reservation.room{id: 2, name: "Room 2"},它们在rooms数组中。注意,它们在不同的内存槽中。
在您的工作案例中,$scope.reservation.room{id: 2, name: "Room 2"}(位于rooms数组中)都指向同一个内存插槽,因为您有等于$scope.reservation.room = $scope.rooms[1];的两个值。这意味着$scope.reservation.room$scope.rooms[1]都指向内存中的同一个对象。
为了解决这个问题,你可以做一些不同于你的工作解决方案的事情。
按如下所示更改ng-repeat

...ng-options="room.id as room.name for room in rooms"...

并将ng-model

....ng-model="reservation.id"....

这将选择选项的id作为EX的选定值。如果选择第一个选项,则模型值将为1,即第一个选项的id
在这种情况下,所选择的模型值是基元(like 1,2,3..)类型数据,则它将不搜索存储器中的对象,而是将获得堆栈的值,并检查选项值,然后选择正确的一个。
这里是DEMO,这将最初选择第二个选项。


如果所选模型值是object,则它将检查所选对象的内存地址和$scope.rooms的所有对象,并检查是否存在匹配元素,如果找到,则选择匹配选项。如果未找到,则不选择任何内容。
如果模型值是像1,2,3..这样的基元,则它将搜索该值并检查是否存在任何匹配的optionvalue,如果找到一个,则它将选择该选项。

kuhbmx9i

kuhbmx9i2#

所以这个问题的关键似乎是ng-options指令中的track by子句。请参见我的updated fiddle正如你将看到的,整个模型都被更新了,而不仅仅是它的ID。文档中说select astrack by不应该一起使用,但是他们用来说明这一点的示例与我的示例有点不同。
由于我还没有收到任何反馈,从官方Angular 渠道对这件事的日期,我会标记为解决这一点,并继续前进。
谢谢大家的帮助。

drkbr07n

drkbr07n3#

加载视图时,选择框没有选定值,因为$scope.reservation中得房间对象与$scope.rooms,event中得房间对象不是同一个对象(如果它们具有相同得值).
这就是为什么您的示例不起作用(fiddle
但这一条很管用:

$scope.rooms = [{id: 1, name: "Room 1"}, {id: 2, name: "Room 2"}];
$scope.reservation = {
    id: 1,
    time: "9AM",
    room: $scope.rooms[1]  // <-- now the reservation room references a valid ng-repeated room
};

请参阅**updated fiddle**
为了避免出现问题,我建议您只将预订的房间ID绑定到选择框的变量。因为它是一个基元类型,比较将通过值进行,这也将解决您的第二个用例。此外,您最好不要在预订对象中复制数据。请参见fiddle
如果需要显示预订(选定)房间的名称,可以很容易地编写一个getRoomById函数来查看房间数组。

rjee0c15

rjee0c154#

仅在值更改时更改范围。

if($scope.reservation.room != $scope.rooms[1])
   $scope.reservation.room = $scope.rooms[1];

相关问题