在AngularJS中,Deep $watch是一个集合

Deep $watch a collection in AngularJS

本文关键字:集合 一个 watch AngularJS Deep      更新时间:2023-09-26

这是我的对象:

$scope.steps = {
        service: {
            selected_service: '',
            selected_month: '',
            selected_year: '',
            selected_day: ''
        },
        payment: {
            selected_dd_type: '',
            cc: {
                selected_card_type: '',
                credit_card_number: '',
                name_on_card: '',
                expiry_month: '',
                expiry_year: ''
            },
            bank_acc: {
                bsb_number: '',
                account_number: '',
                account_holder_name: ''
            }
        },
        agreement: {
            agreement_acceptance: false
        }
    }

以下是$watchCollection:

$scope.$watchCollection('steps.service', function(newVal, oldVal) {
        $scope.canExit = true;
    });
    $scope.$watchCollection('steps.payment', function(newVal, oldVal) {
        $scope.canExit = true;
    }, true);
    $scope.$watchCollection('steps.payment.cc', function(newVal, oldVal) {
            $scope.canExit = true;
    }, true);
    $scope.$watchCollection('steps.payment.bank_acc', function(newVal, oldVal) {
            $scope.canExit = true;
    }, true);
    $scope.$watchCollection('steps.agreement', function(newVal, oldVal) {
            $scope.canExit = true;
    }, true);

一切正常。

必须有一个更好的方法来$watch $scope.steps对象

如果我$watch steps它不会工作。我猜Angular看得不够深

 $scope.$watchCollection('steps', function(newVal, oldVal) {
                $scope.canExit = true;
        }, true);

谢谢您的指导

给你。传递值true作为$watch中的第三个选项:

$scope.$watch('steps', function(newValue, oldValue) {
     // callback on deep watch
     $scope.canExit = true;
}, true);

另外,请确保在watch中添加if条件,因为当您将值赋给$scope.steps时,watch也将被触发。

工作的例子:

var app = angular.module("sa", []);
app.controller("FooController", function($scope) {
  $scope.canExit = false;
  $scope.steps = {
    service: {
      selected_service: '',
      selected_month: '',
      selected_year: '',
      selected_day: ''
    },
    payment: {
      selected_dd_type: '',
      cc: {
        selected_card_type: '',
        credit_card_number: '',
        name_on_card: '',
        expiry_month: '',
        expiry_year: ''
      },
      bank_acc: {
        bsb_number: '',
        account_number: '',
        account_holder_name: ''
      }
    },
    agreement: {
      agreement_acceptance: false
    }
  };
  $scope.reset = function() {
    $scope.canExit = false;
  }
  // Using Math.random() just for demo so that the watch can be invoked
  $scope.changeService = function() {
    $scope.steps.service.selected_service = Math.random();
  }
  $scope.changeDate = function() {
    $scope.steps.payment.cc.selected_card_type = Math.random();
  }
  $scope.changeAgreement = function() {
    $scope.steps.agreement.agreement_acceptance = Math.random();
  }
  $scope.$watch('steps', function(newValue, oldValue) {
    if (newValue && (newValue !== oldValue)) {
      // callback on deep watch
      $scope.canExit = true;
    }
  }, true);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="sa" ng-controller="FooController">
  <button ng-click="changeService()">Change service</button>
  <button ng-click="changeDate()">Change expiry date</button>
  <button ng-click="changeAgreement()">Change agreement</button>
  <br>
  <br>
  <br>Can exit: {{canExit}}
  <button ng-click="reset()">Reset</button>
</div>

1)正如caramiriel在评论中所说,你可以使用带函数参数的$watch;

$watch(
  function(){
     var calculatedVal = /*make all required checks*/;
     return calculatedVal;
  },
  function(newVal){
     $scope.canExit = true;
  }
);

2)更好的选择是完全避免监视,并使用事件/回调,如ng-change;