Javascript &引用;附「;将新对象添加到重复项

Javascript &引用;附「;将新对象添加到重复项,javascript,angularjs,Javascript,Angularjs,我有一个项循环,需要通过API动态替换。问题是,外部范围在被替换时似乎失去了对原始对象的引用。如何使外部作用域注意到数组中某个项的值的变化 (功能(ng){ "严格使用",; ng.模块('应用程序',[]) .controller('ParentController',['$scope', 职能($范围){ $scope.items=[{ 姓名:"富",, 编号:0 }, { 名称:“酒吧”, 编号:1 }, { 名称:“Baz”, 编号:1 }]; } ]) .controller('It

我有一个
项循环
,需要通过API动态替换。问题是,外部范围在被替换时似乎失去了对原始对象的引用。如何使外部作用域注意到数组中某个项的值的变化

(功能(ng){
"严格使用",;
ng.模块('应用程序',[])
.controller('ParentController',['$scope',
职能($范围){
$scope.items=[{
姓名:"富",,
编号:0
}, {
名称:“酒吧”,
编号:1
}, {
名称:“Baz”,
编号:1
}];
}
])
.controller('ItemController',['$scope',
职能($范围){
//伪代码,通常从API获取
var getFromApi=函数(){
返回{
名称:$scope.item.name,
编号:$scope.item.number+1
};
}
$scope.incr=函数(){
$scope.item=getFromApi();
}
}
]);
})(窗口角度)

当您单击以下按钮之一时

  • {{item.name}}({{item.number}) +
这应该更新

{{items}}

……但事实并非如此


您需要知道要更改其属性的项目的键,然后在集合中更改此项目

要声明密钥,可以使用
ng repeat=“(密钥,项)in items”
。然后,该键将作为
ItemController
中的
$scope.key
可用

接下来,由于
ItemController
ParentController
继承了
$scope
,您可以直接访问
ItemController
中的
$scope.items

ItemController.js:

$scope.incr = function() {
  $scope.items[$scope.key] = getFromApi();
}
只有当ItemController是ParentController的子项或继承了它的作用域时,才可能执行此操作。

您可以看到脚本如下运行:

(功能(ng){
"严格使用",;
ng.模块('应用程序',[])
.controller('ParentController',['$scope',
职能($范围){
$scope.items=[{
姓名:"富",,
编号:0
}, {
名称:“酒吧”,
编号:1
}, {
名称:“Baz”,
编号:1
}];
}
])
.controller('ItemController',['$scope',
职能($范围){
//伪代码,通常从API获取
var getFromApi=函数(){
返回{
名称:$scope.item.name,
编号:$scope.item.number+1
};
}
$scope.incr=函数(){
$scope.items[$scope.key]=getFromApi();
}
}
]);
})(窗口角度)

当您单击以下按钮之一时

  • {{item.name}}({{item.number}) +
此更新

{{items}}

…的确如此


您可以使用父数组中项目的索引来替换它

(功能(ng){
"严格使用",;
ng.模块('应用程序',[])
.controller('ParentController',['$scope',
职能($范围){
$scope.items=[{
姓名:"富",,
编号:0
}, {
名称:“酒吧”,
编号:1
}, {
名称:“Baz”,
编号:1
}];
}
])
.controller('ItemController',['$scope',
职能($范围){
//伪代码,通常从API获取
var getFromApi=函数(){
返回{
名称:$scope.item.name,
编号:$scope.item.number+1
};
}
$scope.incr=函数(){
$scope.$parent.items[$scope.$index]=getFromApi();
}
}
]);
})(窗口角度)

当您单击以下按钮之一时

  • {{item.name}{{{item.number}}{{$index}} +
这应该更新

{{items}}

……但事实并非如此


您可以将API调用逻辑移动到父控制器,请参见示例,或者至少替换父范围中的
$scope.items
数组中修改的元素

EDIT:在这里废弃我以前的语句,它不起作用的原因是当您在子作用域的
incr()
方法中分配
$scope.items
时,您没有修改
$scope.items
数组。您只是更改子范围中的变量赋值

因此,在调用
incr()
之前,内存中的变量赋值可能如下所示:

$scope.items =
   item1 -> [ js obj 1 ]
   item2 -> [ js obj 2 ]
   item3 -> [ js obj 3 ]

$scope.item -> [ js obj 1 ]
incr()之后调用第一项:

$scope.items =
   item1 -> [ js obj 1 ]       // still obj 1 here!
   item2 -> [ js obj 2 ]
   item3 -> [ js obj 3 ]

$scope.item -> [ js obj 4 ]    // but entirely new obj here!
示例代码:

  angular.module('app', [])
      .controller('ParentController', ['$scope',

  function ($scope) {
      $scope.items = [{
          name: "Foo",
          number: 0
      }, {
          name: "Bar",
          number: 1
      }, {
          name: "Baz",
          number: 1
      }];

      // fake code, would get from API normally
      var getFromApi = function (item) {
          return {
              name: item.name,
              number: item.number + 1
          };
      }

      $scope.updateItem = function (index) {
          $scope.items[index] = getFromApi($scope.items[index]);
      };
  }])
      .controller('ItemController', ['$scope',

  function ($scope) {
      $scope.incr = function (index) {
          $scope.updateItem(index);
      }
  }]);
显然,如果您想以另一种方式标识修改过的项目,则可以不使用
$index
。上面的代码只是解决问题的最简单的方法。您可以将
getFromApi()
事件保留在子作用域中,只需在那里使用
$scope.items[$index]=getFromApi()
(由于作用域继承)。我只是觉得将该方法保持在父范围内更干净。

另一个(hacky)选项是简单地循环新对象,分配旧对象的变量:

var newItem = getFromApi();
for (var key in newItem) {
  $scope.item[key] = newItem[key];
}
(功能(ng){
"严格使用",;
ng.模块('应用程序',[])
.controller('ParentController',['$scope',
职能($范围){
$scope.items=[{
姓名:"富",,
编号:0
}, {
名称:“酒吧”,
编号:1
}, {
名称:“Baz”,
编号:1
}];
}
])
.controller('ItemController',['$scope',