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

在我的范围内有一个对象数组,我想看每个对象的所有值。

这是我的代码:

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

但是当我修改这些值时,例如我把TITLE改为TITLE2alert('columns changed')从不popup。

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

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

您可以将$watch的第三个参数设置为true

 $scope.$watch('data', function (newVal, oldVal) { /*...*/ }, true); 

请参阅http://docs.angularjs.org/api/ng.$ro​​otScope.Scope#$watch

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

 $scope.$watchCollection('data', function (newVal, oldVal) { /*...*/ }); 

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

深度潜入$ watch中的对象会有性能上的影响。 有时候(例如,当更改只是推送和popup)时,您可能想$观看一个容易计算的值,如array.length。

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

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

但是这不适用于多个数组:

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

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

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

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

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

$ 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); 

以下是您可以通过示例观察范围variables的3种方法的比较:

$ watch()被触发:

 $scope.myArray = []; $scope.myArray = null; $scope.myArray = someOtherArray; 

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

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

$ watch(…,true)由上面的所有事件触发,并且:

 $scope.myArray[0].someProperty = "someValue"; 

还有一件事…

$ watch()是当数组被另一个数组replace时触发的唯一的一个,即使其他数组具有相同的确切内容。

例如, $watch()会触发, $watchCollection()不会:

 $scope.myArray = ["Apples", "Bananas", "Orange" ]; var newArray = []; newArray.push("Apples"); newArray.push("Bananas"); newArray.push("Orange"); $scope.myArray = newArray; 

下面是一个示例JSFiddle的链接,它使用所有不同的手表组合并输出日志消息来指示哪些“手表”被触发:

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

这个解决scheme对我来说工作得很好,我正在做一个指令:

范围。$ watch(attrs.testWatch,function(){…..},true);

真正的作品相当好,并对所有的chnages(添加,删除或修改字段)作出反应。

这里是一个工作的重要人物与它玩。

深入观察AngularJS中的数组

我希望这可以对你有用。 如果您有任何问题,请随时询问,我会尽力帮助:)

在我的情况下,我需要看一个服务,其中包含一个地址对象也被其他几个控制器监视。 我被困在一个循环中,直到我添加了“true”参数,这在看对象时似乎是成功的关键。

 $scope.$watch(function() { return LocationService.getAddress(); }, function(address) { //handle address object }, true); 

设置$watch函数的objectEquality参数(第三个参数)绝对是观察数组的所有属性的正确方法。

 $scope.$watch('columns', function(newVal) { alert('columns changed'); },true); // <- Right here 

Piran也很好地回答了这个问题,并提到了$watchCollection

更多详情

我回答一个已经回答的问题的原因是因为我想指出, 巫师的答案不是好的,不应该使用。

问题是文摘不会立即发生。 他们必须等到当前的代码块完成之后再执行。 因此,观察数组的length可能实际上错过$watchCollection将会捕获的一些重要变化。

假设这个configuration:

 $scope.testArray = [ {val:1}, {val:2} ]; $scope.$watch('testArray.length', function(newLength, oldLength) { console.log('length changed: ', oldLength, ' -> ', newLength); }); $scope.$watchCollection('testArray', function(newArray) { console.log('testArray changed'); }); 

乍看之下,看起来像这样会同时发生,比如在这种情况下:

 function pushToArray() { $scope.testArray.push({val:3}); } pushToArray(); // Console output // length changed: 2 -> 3 // testArray changed 

这工作得很好,但考虑一下:

 function spliceArray() { // Starting at index 1, remove 1 item, then push {val: 3}. $testArray.splice(1, 1, {val: 3}); } spliceArray(); // Console output // testArray changed 

注意,即使数组有一个新元素并丢失了一个元素,结果的长度也是一样的,所以就像$watchlength没有改变。 $watchCollection拿起来了,虽然。

 function pushPopArray() { $testArray.push({val: 3}); $testArray.pop(); } pushPopArray(); // Console output // testArray change 

在相同的块中推入和popup同样的结果。

结论

要观察数组中的每个属性,请使用包含第三个参数(objectEquality)的数组iterator使用$watch ,并将其设置为true。 是的,这是昂贵的,但有时是必要的。

要观察对象何时进入/退出数组,请使用$watchCollection

不要在数组的length属性上使用$watch 。 我能想到的几乎没有什么好的理由可以这样做。

 $scope.changePass = function(data){ if(data.txtNewConfirmPassword !== data.txtNewPassword){ $scope.confirmStatus = true; }else{ $scope.confirmStatus = false; } }; 
  <form class="list" name="myForm"> <label class="item item-input"> <input type="password" placeholder="ใส่รหัสผ่านปัจจุบัน" ng-model="data.txtCurrentPassword" maxlength="5" required> </label> <label class="item item-input"> <input type="password" placeholder="ใส่รหัสผ่านใหม่" ng-model="data.txtNewPassword" maxlength="5" ng-minlength="5" name="checknawPassword" ng-change="changePass(data)" required> </label> <label class="item item-input"> <input type="password" placeholder="ใส่รหัสผ่านใหม่ให้ตรงกัน" ng-model="data.txtNewConfirmPassword" maxlength="5" ng-minlength="5" name="checkConfirmPassword" ng-change="changePass(data)" required> </label> <div class="spacer" style="width: 300px; height: 5px;"></div> <span style="color:red" ng-show="myForm.checknawPassword.$error.minlength || myForm.checkConfirmPassword.$error.minlength">รหัสผ่านต้องมีจำนวน 5 หลัก</span><br> <span ng-show="confirmStatus" style="color:red">รหัสผ่านใหม่ไม่ตรงกัน</span> <br> <button class="button button-positive button-block" ng-click="saveChangePass(data)" ng-disabled="myForm.$invalid || confirmStatus">เปลี่ยน</button> </form>