如果我们使用了angularJS中的$scope.$apply()或者$scope.$digest(),我们很可能会遇到类似下面的错误:
Error: [$rootScope:inprog] $apply already in progress http://errors.angularjs.org/1.3.13/$rootScope/inprog?p0=%24apply at angular.js:63 at beginPhase (angular.js:14755) at Scope.$apply (angular.js:14499) at new <anonymous> (1%20-%20%E5%89%AF%E6%9C%AC.html:10) at Object.invoke (angular.js:4185) at extend.instance (angular.js:8454) at angular.js:7700 at forEach (angular.js:331) at nodeLinkFn (angular.js:7699) at compositeLinkFn (angular.js:7078)
var myModule = angular.module('myModule',[]); myModule.controller("ctrl_1",function($scope){ $scope.value = "aty"; $scope.$apply(); //$scope.$digest(); });
这个错误其实很好理解:angularJS框架本身已经在做脏数据检测了,我们没有必要再手动调用$apply或者$digest。这里自然而然出现了一个疑问:什么时候需要我们手动调用$apply或者$digest,什么时候不需要呢?
目前我只能列出自己在项目中遇到的2种需要手动调用$apply的情况。
情况1:controller中如果有异步操作,比如ajax回调,timeout延时,监听dom事件的回调函数等。可以这么理解:由于异步(延迟)的存在,当开始执行回调函数的时候,angularJS自身controller中的脏值检测已经结束,无法检测到回调函数导致数据的变化。
var myModule = angular.module('myModule',function($scope){
$scope.text = "place";
setTimeout(function(){
$scope.text = "value setted after time out";
$scope.$apply();//必需手动进行脏值检测,否则数据无法刷新到界面
},1000);
var w = angular.element($window);
w.bind('resize',function() {
$rootScope.$apply();
});
});
针对这种情况建议使用angular的内置服务$timeout、$http来代替js、jquery原生的函数。
2.在JQuery代码中修改$scope中的数据。这种情况是在angular框架之外操作$scope中的数据,angular不能检测到数据变化是正常的。
var myModule = angular.module('myModule',function($scope){ $scope.text = "place"; }); $(function(){ angular.bootstrap($("#div1")[0],["myModule"]); $("#btn").click(function(){ var $scope = $("#btn").scope(); $scope.text = "value setted in jquery"; $scope.$apply(); }); })
$apply()有两种形式:
1、接受一个function作为参数,把数据操作放在函数中,执行该function并且触发一轮循环数据检查(推荐):
$scope.getMessage = function(){ setTimeout(function(){ $scope.$apply(function(){ $scope.message = "......" }) },2000); }
2、不接受任何参数,只是触发一轮循环:
$scope.getMessage = function(){ setTimeout(function(){ $scope.message = "......" $scope.$apply(); },2000); }