2013-04-21 123 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