如何深度观察angularjs中的数组?

Fre*_*ind 318 watch angularjs

我的范围中有一个对象数组,我想要观察每个对象的所有值.

这是我的代码:

function TodoCtrl($scope) {
  $scope.columns = [
      { field:'title', displayName: 'TITLE'},
      { field: 'content', displayName: 'CONTENT' }
  ];
   $scope.$watch('columns', function(newVal) {
       alert('columns changed');
   });
}
Run Code Online (Sandbox Code Playgroud)

但是当我修改值时,例如我TITLE改为TITLE2,alert('columns changed')从不弹出.

如何深入观察数组内的对象?

有一个现场演示:http://jsfiddle.net/SYx9b/

Pir*_*ran 525

您可以将第3个参数设置$watchtrue:

$scope.$watch('data', function (newVal, oldVal) { /*...*/ }, true);
Run Code Online (Sandbox Code Playgroud)

请参阅https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch

从Angular 1.1.x开始,您还可以使用$ watchCollection来观看浅表(只是"第一级")的集合.

$scope.$watchCollection('data', function (newVal, oldVal) { /*...*/ });
Run Code Online (Sandbox Code Playgroud)

请参阅https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watchCollection

  • `$ watchCollection`只会观察数组或对象的"第一级",据我所知.如果您需要更深入地观察,上述答案是正确的.http://www.bennadel.com/blog/2566-Scope-watch-vs-watchCollection-In-AngularJS.htm (39认同)
  • 在1.1.x中你现在有`$ watchCollection` (36认同)
  • 当第三个参数采用[布尔值](http://docs.angularjs.org/api/ng.$ro​​otScope.Scope#$watch)时,为什么使用`angular.equals`? (2认同)

小智 50

在你的$ watch中深度潜水物体会产生性能影响.有时(例如,当更改只是推送和弹出时),您可能希望$观察一个容易计算的值,例如array.length.

  • 这应该是评论,而不是答案. (41认同)

Jay*_*com 43

如果你只想看一个数组,你可以简单地使用这段代码:

$scope.$watch('columns', function() {
  // some value in the array has changed 
}, true); // watching properties
Run Code Online (Sandbox Code Playgroud)

但这不适用于多个数组:

$scope.$watch('columns + ANOTHER_ARRAY', function() {
  // will never be called when things change in columns or ANOTHER_ARRAY
}, true);
Run Code Online (Sandbox Code Playgroud)

为了处理这种情况,我通常将我想要观看的多个数组转换为JSON:

$scope.$watch(function() { 
  return angular.toJson([$scope.columns, $scope.ANOTHER_ARRAY, ... ]); 
},
function() {
  // some value in some array has changed
}
Run Code Online (Sandbox Code Playgroud)

正如@jssebastian在评论中指出的那样,JSON.stringify可能更好,angular.toJson因为它可以处理以'$'开头的成员以及可能的其他案例.

  • 请注意,angular.toJson似乎不包含以'$'开头的include成员:angular.toJson({"$ hello":"world"})只是"{}".我使用JSON.stringify()作为替代 (2认同)

Jon*_*wny 21

值得注意的是,在Angular 1.1.x及更高版本中,您现在可以使用$ watchCollection而不是$ watch.虽然$ watchCollection似乎创建了浅表,但它不能像你期望的那样使用对象数组.它可以检测数组的添加和删除,但不能检测数组内对象的属性.

  • 但是,$ watchCollection只能看浅.据我所知,更改数组项的属性(如问题中所示)不会触发事件. (5认同)
  • 这应该是评论,而不是答案. (3认同)

Lui*_*rez 18

以下是使用示例观察范围变量的3种方法的比较:

$ watch()由以下因素触发:

$scope.myArray = [];
$scope.myArray = null;
$scope.myArray = someOtherArray;
Run Code Online (Sandbox Code Playgroud)

$ watchCollection()由以上所有内容触发:

$scope.myArray.push({}); // add element
$scope.myArray.splice(0, 1); // remove element
$scope.myArray[0] = {}; // assign index to different value
Run Code Online (Sandbox Code Playgroud)

$ watch(...,true)由以上所有内容触发:

$scope.myArray[0].someProperty = "someValue";
Run Code Online (Sandbox Code Playgroud)

还有一件事...

$ watch()是唯一一个在用另一个数组替换数组时触发的,即使该另一个数组具有相同的确切内容.

例如哪里$watch()会开火而$watchCollection()不会:

$scope.myArray = ["Apples", "Bananas", "Orange" ];

var newArray = [];
newArray.push("Apples");
newArray.push("Bananas");
newArray.push("Orange");

$scope.myArray = newArray;
Run Code Online (Sandbox Code Playgroud)

下面是一个示例JSFiddle的链接,它使用所有不同的监视组合并输出日志消息来指示触发了哪些"监视":

http://jsfiddle.net/luisperezphd/2zj9k872/


Jin*_*Jin 13

$ watchCollection完成你想做的事.以下是从angularjs网站http://docs.angularjs.org/api/ng/type/$rootScope.Scope复制的示例. 虽然方便,但需要考虑性能,尤其是在观看大型集合时.

  $scope.names = ['igor', 'matias', 'misko', 'james'];
  $scope.dataCount = 4;

  $scope.$watchCollection('names', function(newNames, oldNames) {
     $scope.dataCount = newNames.length;
  });

  expect($scope.dataCount).toEqual(4);
  $scope.$digest();

  //still at 4 ... no changes
  expect($scope.dataCount).toEqual(4);

  $scope.names.pop();
  $scope.$digest();

  //now there's been a change
  expect($scope.dataCount).toEqual(3);
Run Code Online (Sandbox Code Playgroud)

  • OP指定了一个对象数组.您的示例使用字符串数组,但$ watchCollection不适用于对象数组. (13认同)