我想用一些jQuery ajax调用返回的数据更新Angular范围。我想从Angular外部调用Ajax的原因是:a)我希望调用尽可能快地返回,因此它应该在document.ready之前启动.b)有多个调用初始化多个复杂模型页面网页应用;调用之间有依赖关系,我不想在多个Angular控制器中复制任何逻辑。
这是控制器的一些代码。请注意,代码有些简化以适应此处。
$scope.character = {};
$scope.attributeArray = [];
$scope.skillArray = [];
这样做的原因是角色的属性和技能是对象,但是我使用ng-repeat显示它们,所以我需要它们作为数组。
$scope.$watch('character',function(){
$scope.attributeArray = getAttributeArray($scope.character);
$scope.skillArray = getSkillArray($scope.character);
});
理论上,当$ scope.character发生变化时,这段代码会更新两个数组。 现在来了困难的部分。我试过用两种方式更新$ scope.character:
characterRequestNotifier.done(function() { // this is a jQuery deferred object
$scope.$apply(function(){ // otherwise it's happening outside the Angular world
$scope.character = CharacterRepository[characterId]; // initialized in the jquery ajax call's return function
});
});
这有时会导致$digest is already in progress
错误。第二个版本使用我写的服务:
repository.getCharacterById($routeParams.characterId, function(character){
$scope.character = character;
});
,其中
.factory('repository', function(){
return {
getCharacterById : function(characterId, successFunction){
characterRequestNotifier.done(function(){
successFunction( CharacterRepository[characterId] );
});
}
};
});
这并不总是触发$ watch。
最后,问题是:我怎样才能完成这项任务(没有随机错误,我无法确定其来源)?我的方法是否存在根本性的错误?
编辑:
在这里尝试这个jsfiddle: http://jsfiddle.net/cKPMy/3/ 这是我的代码的简化版本。有趣的是,它不会在延迟解决时触发$ watch。
答案 0 :(得分:1)
可以通过选中$scope.$$phase
来检查是否可以安全地拨打$ apply。如果它返回一些真实的东西 - 例如。 '$apply'
或'$digest'
- 将您的代码包装在$apply
调用中将导致该错误消息。
就我个人而言,我会选择第二种方法,但使用$q
服务 - AngularJS的承诺实施。
.factory('repository', function ($q) {
return {
getCharacterById : function (characterId) {
var deferred = $q.defer();
characterRequestNotifier.done(function () {
deferred.resolve(CharacterRepository[characterId]);
});
return deferred.promise;
}
};
});
由于AngularJS本身支持此承诺实现,因此您可以将代码更改为:
$scope.character = repository.getCharacterById(characterId);
当AJAX调用完成后,承诺得到解决,AngularJS将自动处理绑定,触发$watch
等。
添加小提琴后编辑
由于jQuery promise在服务中使用,因此Angular无法知道何时解析了该promise。要修复它,您需要在$apply
调用中包装解析。 Updated fiddle。这解决了小提琴,我希望它也能解决你的真正问题。