angularJS報錯$apply already in progress
阿新 • • 發佈:2019-01-26
如果我們使用了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,什麼時候不需要呢?
情況1:controller中如果有非同步操作,比如ajax回撥,timeout延時,監聽dom事件的回撥函式等。可以這麼理解:由於非同步(延遲)的存在,當開始執行回撥函式的時候,angularJS自身controller中的髒值檢測已經結束,無法檢測到回撥函式導致資料的變化。
var myModule = angular.module('myModule', []); myModule.controller("ctrl_1",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', []);
myModule.controller("ctrl_1",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);
}