Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/416.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript $apply已在使用自定义指令和事件进行中_Javascript_Jquery_Angularjs_Events_Angularjs Directive - Fatal编程技术网

Javascript $apply已在使用自定义指令和事件进行中

Javascript $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

我正在围绕第三方jQuery插件编写一个自定义指令。第三方jQuery插件使用事件处理数据更新,因此my指令监视事件并使用$apply确保正确更新从控制器传入的数据。我还希望能够更新插件中的数据,这样我就有了一个方法,可以通过我自己在指令范围内的方法调用来修改/更新数据。但是,当angular指令触发my指令上的方法调用时(在本例中,通过ng单击),会导致“$apply ready in progress”角度错误。我认为这是因为Angular的内置指令已经为我调用了$apply或$digest或类似的东西。我已经找到了一种使用$timeout来解决这个问题的方法,但它感觉像是一种“ick,don't do that”之类的东西。当第三方插件通过与插件的正常交互触发自己的事件时,一切正常(即,我没有得到$apply in progress错误,并且数据按照我预期的方式在作用域上更新)

有谁能帮我想出一个更好的方法来做我想做的事吗?我在这里提供了示例代码和一个提琴来说明问题(这不是真正的指令,它简单得多,而且我无法控制第三方jQuery插件和它抛出的事件等)

更新 更好地说明问题的新代码:

HTML


控制器编号视图:

  • {{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}
添加另一个数字”, 替换:正确, 链接:功能(范围、元素){ scope.addAnotherNumber=函数(){ //1.这样做有效,取消对此的注释并注释掉2以查看 //$timeout(function(){element.triggerHandler('my-custom-event',[Math.random()*20]); //2.这会导致“$apply ready in progress”错误 element.triggerHandler('my-custom-event',[Math.random()*20]) }; 元素.on('my-custom-event',函数(e,编号){ 作用域$apply(函数(){ 范围.编号.推送(编号); }); }); } }; });
您可以尝试在如下函数中包装对$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);
    });
};