我有一个ItemsService
,它为一对控制器/视图提供了一系列项目。
在第一种情况(列表视图)中,服务中某个项目的更改会导致UI发生变化 - 一切都很好。
在第二种情况(详细视图)中,项目绑定正常但如果项目在服务中发生更改则不会更新。
我错过了什么?
Plunker:http://plnkr.co/edit/Jlk2xFfry4N8Wqfw31Em?p=preview
服务:
app.factory('ItemsService', function ($rootScope) {
// omitted code to update items - this works fine
var itemsById = [];
var itemsArray = [];
function updateItems(itemUpdate) {
itemsById[itemUpdate.Id] = itemUpdate;
while (itemsArray.length > 0) {
itemsArray.pop();
}
for (var key in itemsById) {
itemsArray.push(itemsById[key]);
};
}
return {
items: itemsArray,
itemsById: itemsById,
}
});
列出项目的控制器:
app.controller('ItemsController', function ($scope, ItemsService) {
$scope.items = ItemsService.items;
});
列表视图:
<table class="table" data-ng-controller="ItemsController">
<tr data-ng-repeat="item in items">
<td>{{item.Name}}</td>
</tr>
</table>
详情视图的控制器:
//$stateParams is part of Angular UI Routing - this works because the correct item is selected and displayed - it just doesn't update
app.controller('ItemController', function ($scope, $stateParams, ItemService) {
$scope.item = ItemService.itemsById[$stateParams.id];
});
详情视图:
<div data-ng-controller="ItemController">
{{item.Name}}
</div>
修改
如果我在一个函数中包装调用以在第二种情况下分配项目,那么它可以工作:
app.controller('ItemController', function ($scope, $stateParams, ItemService) {
$scope.item = function () { return ItemService.itemsById[$stateParams.id]; }
});
详情视图:
<div data-ng-controller="ItemController">
{{item().Name}}
</div>
但我的理解是,绑定到像这样的函数调用是不好的做法..
答案 0 :(得分:1)
在您的示例代码中实际上有很多事情同时进行,我不确定代码的哪一部分实际上是您关心的,以及哪些部分仅用于演示。
这是一个正在运作的Plunkr: http://plnkr.co/edit/mjUtRSfFwYLGPC17O0st?p=preview
我改变了一些事情。首先,在工厂中,您返回的是硬编码的对象数组,但是初始化它们的方式使每个对象都是唯一的,而不是相同的元素。因此,更新它们只会在每个位置更新一个副本:return {
items: [{Id: '1', Name: 'TestItem1'}, {Id: '2', Name: 'TestItem2'}],
itemsById: {'1': {Id: '1', Name: 'TestItem1'}, '2': {Id: '2', Name: 'TestItem2'} },
}
也许你刚刚为演示目的做了这个?但是在更新例程中,当您改变这些数组时,AngularJS无法跟踪这些更改,因为它们都会在每次调用时指向不同的对象。
接下来,我将服务从工厂更改为服务。它们都可以工作,但我发现当你在这样的事情上做出这样的事情时,服务模式通常更容易理解 - 在API面前单身。 Javascript非常容易受到如何引用对象的小错误的影响。例如,当你这样做时:
itemsById[itemUpdate.Id] = itemUpdate;
这会让你遇到很多麻烦,特别是在Angular。往往会发生在其他地方你做这样的事情:
var myItem = ThatService.itemsById[123];
但是现在你有了旧拷贝的引用。使用新副本更新条目时,屏幕不会更新。这是因为myItem指向旧副本,即使您已更新了包含项目的数组。也就是说,JS中的引用指向目标对象,而不是指向其存储集合中的插槽。更新存储集合需要更像:
myCollection[Id] = myCollection[Id] || {};
angular.extend(myCollection[Id], myNewData);
这种方式无论谁有对象的引用,都会得到所需的更新。
如果您有任何疑问,请查看Plunkr并告诉我。如果您需要有关确切用例的详细信息,我很乐意回复您的评论!