Javascript $apply已在使用自定义指令和事件进行中
我正在围绕第三方jQuery插件编写一个自定义指令。第三方jQuery插件使用事件处理数据更新,因此my指令监视事件并使用$apply确保正确更新从控制器传入的数据。我还希望能够更新插件中的数据,这样我就有了一个方法,可以通过我自己在指令范围内的方法调用来修改/更新数据。但是,当angular指令触发my指令上的方法调用时(在本例中,通过ng单击),会导致“$apply ready in progress”角度错误。我认为这是因为Angular的内置指令已经为我调用了$apply或$digest或类似的东西。我已经找到了一种使用$timeout来解决这个问题的方法,但它感觉像是一种“ick,don't do that”之类的东西。当第三方插件通过与插件的正常交互触发自己的事件时,一切正常(即,我没有得到$apply in progress错误,并且数据按照我预期的方式在作用域上更新) 有谁能帮我想出一个更好的方法来做我想做的事吗?我在这里提供了示例代码和一个提琴来说明问题(这不是真正的指令,它简单得多,而且我无法控制第三方jQuery插件和它抛出的事件等) 更新 更好地说明问题的新代码: HTMLJavascript $apply已在使用自定义指令和事件进行中,javascript,jquery,angularjs,events,angularjs-directive,Javascript,Jquery,Angularjs,Events,Angularjs Directive,我正在围绕第三方jQuery插件编写一个自定义指令。第三方jQuery插件使用事件处理数据更新,因此my指令监视事件并使用$apply确保正确更新从控制器传入的数据。我还希望能够更新插件中的数据,这样我就有了一个方法,可以通过我自己在指令范围内的方法调用来修改/更新数据。但是,当angular指令触发my指令上的方法调用时(在本例中,通过ng单击),会导致“$apply ready in progress”角度错误。我认为这是因为Angular的内置指令已经为我调用了$apply或$digest
控制器编号视图:
- {{number}
指令视图
加(鬼鬼祟祟的)号码
JavaScript
(function(){
var data = [1, 2, 3];
window.getData = function(){ return data; }
window.addNumber = function(number){
data.push(number);
$('.adder-directive').trigger('my-custom-event', [number]);
};
$(document).on('click', '#sneaky-adder', function(){
var newNum = (Math.random() * 20) + ' sneaky :)';
data.push(newNum);
$('.adder-directive').trigger('my-custom-event', [newNum]);
});
})();
angular.module('blarf', [])
.controller('blah', function($scope){
$scope.numbers = getData();
})
.directive('someAwesomeDirective', function($timeout){
return {
restrict: 'E',
scope: {
numbers: '=',
},
template: '<div class="adder-directive"><ul><li ng-repeat="number in numbers">{{number}}</li></ul><button type="button" id="adder" ng-click="addAnotherNumber()">Add Another Number</button></div>',
replace: true,
link: function(scope, element){
scope.addAnotherNumber = function(){
// 1.
/*$timeout(function(){
var newNum = Math.random() * 20;
addNumber(newNum);
});*/
// 2.
var newNum = Math.random() * 20;
addNumber(newNum);
};
$(element).on('my-custom-event', function(e, number){
// 3.
scope.$apply(function(){
scope.numbers = getData();
});
});
}
};
});
angular.module('blarf', [])
.controller('blah', function($scope){
$scope.numbers = [1,2,3];
})
.directive('someAwesomeDirective', function($timeout){
return {
restrict: 'E',
scope: {
numbers: '=',
},
template: '<div><ul><li ng-repeat="number in numbers">{{number}}</li></ul><button type="button" ng-click="addAnotherNumber()">Add Another Number</button></div>',
replace: true,
link: function(scope, element){
scope.addAnotherNumber = function(){
// 1. This works, uncomment this and comment out 2 to see
//$timeout(function(){ element.triggerHandler('my-custom-event', [Math.random() * 20])});
// 2. This causes an "$apply already in progress" error
element.triggerHandler('my-custom-event', [Math.random() * 20])
};
element.on('my-custom-event', function(e, number){
scope.$apply(function(){
scope.numbers.push(number);
});
});
}
};
});
(函数(){
var数据=[1,2,3];
window.getData=function(){return data;}
window.addNumber=函数(编号){
数据推送(数字);
$('.adder指令').trigger('my-custom-event',[number]);
};
$(文档).on('单击','偷偷摸摸的加法器',函数()){
var newNum=(Math.random()*20)+“鬼鬼祟祟:)”;
数据推送(newNum);
$('.adder指令').trigger('my-custom-event',[newNum]);
});
})();
角度模块('blarf',[]))
.controller('blah',函数($scope){
$scope.numbers=getData();
})
.directive('someAwesomeDirective',函数($timeout){
返回{
限制:'E',
范围:{
编号:'=',
},
模板:“- {{number}
添加另一个数字”,
替换:正确,
链接:功能(范围、元素){
scope.addAnotherNumber=函数(){
// 1.
/*$timeout(函数(){
var newNum=Math.random()*20;
addNumber(newNum);
});*/
// 2.
var newNum=Math.random()*20;
addNumber(newNum);
};
$(元素).on('my-custom-event',函数(e,编号){
// 3.
作用域$apply(函数(){
scope.numbers=getData();
});
});
}
};
});
老东西
HTML
JavaScript
(function(){
var data = [1, 2, 3];
window.getData = function(){ return data; }
window.addNumber = function(number){
data.push(number);
$('.adder-directive').trigger('my-custom-event', [number]);
};
$(document).on('click', '#sneaky-adder', function(){
var newNum = (Math.random() * 20) + ' sneaky :)';
data.push(newNum);
$('.adder-directive').trigger('my-custom-event', [newNum]);
});
})();
angular.module('blarf', [])
.controller('blah', function($scope){
$scope.numbers = getData();
})
.directive('someAwesomeDirective', function($timeout){
return {
restrict: 'E',
scope: {
numbers: '=',
},
template: '<div class="adder-directive"><ul><li ng-repeat="number in numbers">{{number}}</li></ul><button type="button" id="adder" ng-click="addAnotherNumber()">Add Another Number</button></div>',
replace: true,
link: function(scope, element){
scope.addAnotherNumber = function(){
// 1.
/*$timeout(function(){
var newNum = Math.random() * 20;
addNumber(newNum);
});*/
// 2.
var newNum = Math.random() * 20;
addNumber(newNum);
};
$(element).on('my-custom-event', function(e, number){
// 3.
scope.$apply(function(){
scope.numbers = getData();
});
});
}
};
});
angular.module('blarf', [])
.controller('blah', function($scope){
$scope.numbers = [1,2,3];
})
.directive('someAwesomeDirective', function($timeout){
return {
restrict: 'E',
scope: {
numbers: '=',
},
template: '<div><ul><li ng-repeat="number in numbers">{{number}}</li></ul><button type="button" ng-click="addAnotherNumber()">Add Another Number</button></div>',
replace: true,
link: function(scope, element){
scope.addAnotherNumber = function(){
// 1. This works, uncomment this and comment out 2 to see
//$timeout(function(){ element.triggerHandler('my-custom-event', [Math.random() * 20])});
// 2. This causes an "$apply already in progress" error
element.triggerHandler('my-custom-event', [Math.random() * 20])
};
element.on('my-custom-event', function(e, number){
scope.$apply(function(){
scope.numbers.push(number);
});
});
}
};
});
角度模块('blarf',[])
.controller('blah',函数($scope){
$scope.number=[1,2,3];
})
.directive('someAwesomeDirective',函数($timeout){
返回{
限制:'E',
范围:{
编号:'=',
},
模板:“- {{number}
您可以尝试在如下函数中包装对$apply的调用:
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
您可以将逻辑放入一个由按钮(从angular)和事件(仅在angular外部调用)调用的函数中:
如果没有范围,$apply,scope属性不会更新?@Narretz UPDATE:事实上,如果删除$scope,我发布的fiddle中的$apply数据仍然会正确更新,因为ng click正确地安排了$digest或其他内容,但在我编写的实际自定义指令中,还有其他一些angular不知道的方法可以使数据发生变异。我将看看是否可以以演示删除$scope的方式更新fiddle。$apply会破坏绑定。在
$timeout
中包装$apply
非常好,并且比访问$$phase
更可取。我在尝试找到问题的答案时,到处都看到了这种解决方案,并且担心使用它因为我看到评论说“不要那样做”。这是一种老套的解决方法还是一种有效的、有角度的方法来处理这个问题?好吧,你应该努力做到a)不使用范围。$apply放在第一位,b)除非绝对必要,否则不要求助于safeApply。但是与运行在Angular摘要周期之外的jQuery插件进行交互时,您通常需要执行类似的操作,或者重新编写整个插件以使其与Angular更兼容。$scope.$apply的整个概念基本上是一个类似Object的解决方法。观察。事实上,“安全应用”至少在角型芯内部使用一次。当然,在某些情况下,有必要使用这种策略
scope.handleNumber(number) {
scope.numbers.push(number);
};
scope.addAnotherNumber = function() {
scope.handleNumber(Math.random() * 20);
};
element.on('my-custom-event', function(e, number) {
scope.$apply(function() {
scope.handleNumber(number);
});
};