AngularJS报错 $digest already in progress


官网上有对这个问题的详细解释和解决方法: https://docs.angularjs.org/error/$rootScope/inprog?p0=$digest。

下面我简单地讲一下原因和解决方法:

假设我现在定义了一个指令,该指令会监听 attr.setFocusIf的值,当该值发生变化时,元素element获得焦点。

myApp.directive('setFocusIf', function() {
  return {
    link: function($scope, $element, $attr) {
      $scope.$watch($attr.setFocusIf, function(value) {
        if ( value ) { $element[0].focus(); }
      });
    }
  };
});
假设我在html中是这样使用这个指令的

<input set-focus-if="hasFocus" ng-focus="msg='has focus'">
<button ng-click="hasFocus = true">Focus</button>

此时,有两种方式触发 ngFocus动作,第一种方式的执行过程如下:

(1)点击input表单

(2)input表单获得焦点

(3)触发ng-focus,启动一个新的 $apply() 将 msg的值设置为 "has fcous"

第二种方式的过程如下:

(1)点击按钮

(2)ng-click被触发,启动一个新的$apply() 将hasFcous的值设置为true

(3)$apply()启动 $digest() ,该$digest触发 setFocusIF指令中的$watch回调函数

(4)$watch回调函数执行,使得input表单获取焦点

(5)ng-focus指令被触发,启动一个新的$apply()将 msg的值设置为 "has fcous" (问题出现了,在一个$digest中启动了另外一个$digest ,因此抛出异常)

解决方法:

 知道原因之后,解决方法也很简单,只要第(5)步在一个干净的环境启用新的$digest即可。使用$timeout(fn, 0 , false)。最有一个false告诉angularjs不要将该fn包含在一个$apply()中。 

修改 指令的代码如下:

myApp.directive('setFocusIf', function($timeout) {
  return {
    link: function($scope, $element, $attr) {
      $scope.$watch($attr.setFocusIf, function(value) {
        if ( value ) {
          $timeout(function() {
            // We must reevaluate the value in case it was changed by a subsequent
            // watch handler in the digest.
            if ( $scope.$eval($attr.setFocusIf) ) {
              $element[0].focus();
            }
          }, 0, false);
        }
      });
    }
  }
});

此时运行即无异常


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值