在我的作用域中有一个对象数组,我想观察每个对象的所有值。

这是我的代码:

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

但是当我修改值时,例如我将TITLE更改为TITLE2,警报('列已更改')从未弹出。

如何深度观看数组内的对象?

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


当前回答

你可以设置$watch的第3个参数为true:

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

见https://docs.angularjs.org/api/ng/type/ rootScope.Scope #美元的手表

从Angular 1.1开始。x你也可以使用$watchCollection来观看浅表(只是“第一层”)的集合。

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

见https://docs.angularjs.org/api/ng/type/ rootScope.Scope # watchCollection美元

其他回答

值得注意的是,在Angular 1.1中。x和以上,你现在可以使用$watchCollection而不是$watch。虽然$watchCollection看起来创建的是浅表,所以它不能像你期望的那样处理对象数组。它可以检测数组的添加和删除,但不能检测数组内对象的属性。

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

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

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

更详细地

我之所以要回答一个已经回答过的问题,是因为我想指出wizardwerdna的答案不是一个好的答案,不应该被使用。

问题是,摘要不会立即发生。它们必须等到当前代码块完成后才能执行。因此,观察数组的长度实际上可能会错过$watchCollection将捕捉到的一些重要更改。

假设如下配置:

$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

请注意,即使数组有一个新元素和丢失了一个元素,结果的长度是相同的,因此对于$watch而言,长度没有改变。不过$watchCollection发现了它。

function pushPopArray() {
    $testArray.push({val: 3});
    $testArray.pop();
}
pushPopArray();

// Console output
// testArray change

同样的结果也发生在同一个块的push和pop操作中。

结论

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

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

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

在$watch中深潜一个对象会对性能造成影响。有时(例如,当更改仅为推和弹出时),您可能希望$watch一个容易计算的值,例如array.length。

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

你可以设置$watch的第3个参数为true:

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

见https://docs.angularjs.org/api/ng/type/ rootScope.Scope #美元的手表

从Angular 1.1开始。x你也可以使用$watchCollection来观看浅表(只是“第一层”)的集合。

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

见https://docs.angularjs.org/api/ng/type/ rootScope.Scope # watchCollection美元