AngularJS 范围和延迟 [英] AngularJS Scopes and Deferreds

查看:22
本文介绍了AngularJS 范围和延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个服务做一些困难的事情并返回一个承诺:

.factory('myService', function($q) {返回 {doSomethingHard:函数(){var deferred = $q.defer();设置超时(函数(){deferred.resolve("我完成了!");}, 1000);返回 deferred.promise;}};})

我有一个控制器,它使用该服务向作用域添加一个函数:

.controller('MyCtrl', function($scope, myService) {$scope.doSomething = function() {var promise = myService.doSomethingHard();promise.then(函数(结果){警报(结果);});};})

我使用指令通过解析属性来调用该控制器函数:

.directive('myDirective', function($parse) {返回 {链接:函数(范围,EL,属性){var myParsedFunction = $parse(attr.myDirective);el.bind('点击', function() {myParsedFunction(范围);});}};})

使用模板

<button my-directive="doSomething()">按钮</button>

点击按钮触发事件监听器,它调用控制器函数doSomething,它调用服务函数doSomethingHard,它返回一个promise,THAT IS NEVER已解决.

这里有一个小提琴:

http://jsfiddle.net/nicholasstephan/RgKaT/

是什么?

谢谢.

感谢 Maksym H.,看起来像在 $scope.$apply() 中包装承诺解析使它在控制器中触发.我有一个工作小提琴 http://jsfiddle.net/RgKaT/4/.但我真的很想将范围排除在我的服务之外.

我也很想知道为什么会这样.或者更好的是,为什么它在包装在作用域中时不解决承诺就不起作用.在考虑需要消化更改的属性时,整个 Angular 世界与常规 Javascript 世界的类比是有道理的,但这是一个承诺......带有回调函数.$q 是否只是将承诺标记为已解决并等待范围消化该属性更新并触发其已解决的处理程序函数?

解决方案

这是另一种方法:尝试在指令中定义作用域并将此属性绑定到期望父作用域.

.directive('myDirective', function() {返回 {范围:{ myDirective: "=" },//或 { myParsedFunction: "=myDirective" },链接:函数(范围,EL,属性){el.bind('点击', function() {scope.myDirecive(scope);//或 scope.myParsedFunction(scope)});}};})

但主要是在一段时间后解决它时运行摘要:

.factory('myService', function($q, $timeout) {返回 {doSomethingHard:函数(){alert('3. 做一些困难的事情');var deferred = $q.defer();//使用 $timeout 因为它与 promises 一起工作得更好$超时(功能(){alert('4. 解决延迟');deferred.resolve('Hello World!');//这里...}, 1000);返回 deferred.promise;}};})

jsFiddle

附言确保您将方法作为父作用域的模型传递,而不是通过 HTML 中的()"应用此方法

I have a service that does something hard and returns a promise:

.factory('myService', function($q) {

    return {
        doSomethingHard: function() {
            var deferred = $q.defer();

            setTimeout(function() {
                deferred.resolve("I'm done!");
            }, 1000);

            return deferred.promise;
        }
    };
})

I have a controller that adds a function to the scope using that service:

.controller('MyCtrl', function($scope, myService) {

    $scope.doSomething = function() {
        var promise = myService.doSomethingHard();

        promise.then(function(result) {
            alert(result);
        });
    };

})

I use a directive to call that controller function by parsing an attribute:

.directive('myDirective', function($parse) {
    return {
        link: function(scope, el, attr) {

            var myParsedFunction = $parse(attr.myDirective);

            el.bind('click', function() {
                myParsedFunction(scope);
            });
        }
    };
})

with the template

<div ng-controller="MyCtrl">
    <button my-directive="doSomething()">The Button</button>
</div>

Clicking the button triggers the event listener, which calls the controller function doSomething, which calls the service function doSomethingHard, which returns a promise, THAT IS NEVER RESOLVED.

Whole thing up on a fiddle here:

http://jsfiddle.net/nicholasstephan/RgKaT/

What gives?

Thanks.

EDIT: Thanks to Maksym H., It looks like wrapping the promise resolve in $scope.$apply() makes it fire in the controller. I've got a working fiddle up http://jsfiddle.net/RgKaT/4/. But I'd really like to keep the scope out of my services.

I'd also really like to know why this works. Or better yet, why it doesn't work without resolving the promise while wrapped in a scope apply. The whole Angular world vs regular Javascript world analogy makes sense when thinking about properties as changes need to be digested, but this is a promise... with callback functions. Does $q just flag the promise as resolved and wait for the scope to digest that property update and fire its resolved handler functions?

解决方案

Here is another way: Try to define scope in directive and bind this attr to expect parent scope.

.directive('myDirective', function() {
  return {
    scope: { myDirective: "=" }, // or { myParsedFunction: "=myDirective" },
    link: function(scope, el, attr) {

        el.bind('click', function() {
            scope.myDirecive(scope); // or scope.myParsedFunction(scope)
        });
    }
  };
})

But the main thing is to run digest when you resolving it after some time:

.factory('myService', function($q, $timeout) {

    return {
        doSomethingHard: function() {
            alert('3. doing something hard');

            var deferred = $q.defer();

            // using $timeout as it's working better with promises
            $timeout(function() {
                alert('4. resolving deferred');
                deferred.resolve('Hello World!'); // Here...
            }, 1000);

            return deferred.promise;
        }
    };
})

jsFiddle

P.S. Make sure you are passing method as model of parent scope not applying this by "()" in HTML

<button my-directive="doSomething">Button</button>

这篇关于AngularJS 范围和延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆