AngularJS(和坦率地说,JavaScript)的新手,但是从我收集的内容中,只有在有角度的雷达之外发生变化时,才需要显式调用$ scope。$ apply()。下面的代码(粘贴自this plunker)让我觉得它不是需要通话的情况,但这是我能让它发挥作用的唯一方法。我应该采取不同的方法吗?
的index.html:
<html ng-app="repro">
<head>
...
</head>
<body class="container" ng-controller="pageController">
<table class="table table-hover table-bordered">
<tr class="table-header-row">
<td class="table-header">Name</td>
</tr>
<tr class="site-list-row" ng-repeat="link in siteList">
<td>{{link.name}}
<button class="btn btn-danger btn-xs action-button" ng-click="delete($index)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
</tr>
</table>
</body>
</html>
的script.js:
var repro = angular.module('repro', []);
var DataStore = repro.service('DataStore', function() {
var siteList = [];
this.getSiteList = function(callback) {
siteList = [
{ name: 'One'},
{ name: 'Two'},
{ name: 'Three'}];
// Simulate the async delay
setTimeout(function() { callback(siteList); }, 2000);
}
this.deleteSite = function(index) {
if (siteList.length > index) {
siteList.splice(index, 1);
}
};
});
repro.controller('pageController', ['$scope', 'DataStore', function($scope, DataStore) {
DataStore.getSiteList(function(list) {
$scope.siteList = list; // This doesn't work
//$scope.$apply(function() { $scope.siteList = list; }); // This works
});
$scope.delete = function(index) {
DataStore.deleteSite(index);
};
}]);
答案 0 :(得分:5)
setTimeout(function() { callback(siteList); }, 2000);
此行将带您进入Anglar的摘要循环之外。您只需将setTimeout
替换为Angular的$timeout
包装器(您只需将其注入DataStore服务),就不需要$scope.$apply
。
答案 1 :(得分:2)
setTimeout
是async
事件,被视为超出angular
上下文,因此它不会运行摘要周期。您需要在执行此类操作时手动运行它,但首选使用$timeout
。
相反,angular会提供$timeout
服务,其工作方式与setTimeout
相同,但在执行回调函数后,它会调用$scope.$apply()
$timeout(function() { callback(siteList); }, 2000);
关于
$timeout
的特殊之处在于它运行摘要周期 更安全的方式。它为您提供保证,它不会与任何冲突 目前正在运行摘要周期。在幕后,当您在$timeout
内调用函数时,它会通过检查$scope.root.$$phase
来检查是否有任何摘要周期在运行,如果它在digest
阶段,它会放置该摘要在队列中循环并在完成该摘要循环后运行它。