在AngularJs中,为什么一个作用域变量在更改时会更新,而另一个非常类似的变量则不会更新?

在AngularJs中,为什么一个作用域变量在更改时会更新,而另一个非常类似的变量则不会更新?,angularjs,Angularjs,我有一个ItemsService,它为一对控制器/视图提供一个项目数组 在第一种情况下(列表视图),服务中某个项目的更改会导致UI的更改—一切正常 在第二种情况下(详细视图),项目绑定良好,但如果项目在服务中发生更改,则不会更新 我错过了什么 普朗克: 服务: app.factory('ItemsService', function ($rootScope) { // omitted code to update items - this works fine var ite

我有一个
ItemsService
,它为一对控制器/视图提供一个项目数组

在第一种情况下(列表视图),服务中某个项目的更改会导致UI的更改—一切正常

在第二种情况下(详细视图),项目绑定良好,但如果项目在服务中发生更改,则不会更新

我错过了什么

普朗克:

服务:

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>
<div data-ng-controller="ItemController">
    {{item().Name}}
</div>
详细视图:

//$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>
<div data-ng-controller="ItemController">
    {{item().Name}}
</div>

{{item().Name}

但我的理解是,像这样绑定到函数调用是一种不好的做法。

在示例代码中实际上同时有很多东西,我不确定代码的哪一部分是您真正关心的,哪一部分只是为了演示

这是一个有效的例子:

我改变了一些事情。首先,在工厂中,您返回的是硬编码的对象数组,但初始化它们的方式使每个对象都是唯一的,而不是相同的元素。因此,更新它们只能在每个位置更新一份副本:

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;
这会给你带来很多麻烦,尤其是在你的生活中。在其他地方,你可能会这样做:

var myItem = ThatService.itemsById[123];
但是现在你有了一个对旧版本的引用。使用新副本更新条目时,屏幕不会更新。这是因为myItem指向旧副本,即使您已经更新了保存这些项的数组。也就是说,JS中的引用指向目标对象,而不是其存储集合中的插槽。更新存储集合需要执行以下操作:

myCollection[Id] = myCollection[Id] || {};
angular.extend(myCollection[Id], myNewData);
这样,无论谁拥有对对象的引用,它都将获得所需的更新


请看一下Plunkr,如果您有任何问题,请告诉我。如果您需要关于您的确切用例的更多细节,我很乐意回复您

请提供jsfiddle或plunker版本。它可以节省我们测试和发现问题的时间。这样做可能会更好,不必每次都重新构建条目数组。对于特定项,只需迭代数组并返回object@hutingung-很遗憾,我不能,它绑定到提供项目的后端服务。所有相关的代码都在这里。@charlietfl-这不是问题所在。items数组在列表视图中工作正常。当我通过id从关联数组中获取一个项时,它会更新,然后传播失败。这就是为什么我说从同一主数组中提取。javascript也没有关联数组。你失去了两人之间的联系-你是个明星。我认为这与参考资料有关,但没有发现这个问题。最后两行代码修复了它,但是您是否介意解释一下语法,这里到底发生了什么?好的-第一行是空合并,第二行将
myNewData
中的所有属性添加到该数组位置的项中。非常感谢Chad。顺便问一下,有没有一个工具可以帮助调试这样的参考问题?不幸的是,我还没有找到一个特定于Angular的工具。不过,我发现ESLint在构建过程中确实很有帮助。导致这种情况的标准模式是直接分配给对象,如
myObj={}
myArr=[]
。当它们被发现时,扫描和警告/出错非常容易。我就是这么做的。