2013-04-21 122 views
2

我有做一些事情很难,并返回一个承诺服务:AngularJS范围和Deferreds

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

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

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

      return deferred.promise; 
     } 
    }; 
}) 

我有一个控制器,使用该服务增加了一个功能,范围:

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

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

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

}) 

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

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

      var myParsedFunction = $parse(attr.myDirective); 

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

与模板

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

单击该按钮会触发事件侦听器,它调用控制器功能doSomething,它调用服务功能doSomethingHard,它返回一个承诺,是永远不会分辨

整件事在这里小提琴:

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

是怎么回事?

谢谢。

编辑:感谢Maksym阁下,它看起来像包装承诺决心在$scope.$apply()使它在控制器的火灾。我有一个工作小提琴http://jsfiddle.net/RgKaT/4/。但我真的很想保持我的服务范围。

我也很想知道为什么这个工程。或者更好的是,为什么它在包装在范围应用中时不解决承诺是行不通的。整个Angular世界与常规的Javascript世界比喻在考虑属性变化时需要消化时才有意义,但这是一个承诺...具有回调函数。 $ q是否只将promise标记为已解决,并等待范围消化该属性更新并释放其已解析的处理函数?

回答

2

这是另一种方法:尝试在指令中定义范围,并绑定此属性以期望父范围。

.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) 
     }); 
    } 
    }; 
}) 

但主要的一点是,当你经过一段时间解决它运行消化:

.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

附:请确保您传递方法的父范围不通过应用此模型“()”中的HTML

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

+0

@nicholas,我已经更新了Plunker上的代码。我希望它能为你工作。 – Maksym 2013-04-21 22:28:16

+0

真棒回答。谢谢。我已经通过将$ rootScope添加到服务中,像你所建议的那样工作。谢谢。但是,我仍然不是很高兴,也不了解这个解决方案(请参阅我的编辑)。 – nicholas 2013-04-22 20:18:41

+0

@nicholas,你不用担心,因为它是原生setTimeout的错。通过使用这个,agnular似乎停止观看解决。在实际的例子中,你可能会使用XHR erquest之类的东西,并成功解决,对吧?但是现在,您可以使用角度$超时提供程序进行测试,该提供程序在角度许诺方面效果更好。而且你可以尝试用XHR请求来解决问题,它应该可以工作。这里更新小提琴(http://jsfiddle.net/RgKaT/6/) – Maksym 2013-04-23 08:44:27

1

只需更换setTimeout$timeout(记住注入$timeout为您服务)。这是一个updated jsFiddle