2013-10-25 5 views
6

Einer meiner AngularJS Controller enthält die folgende Zeile:für Versprechen vor dem Laden Ressource zu lösen Warten

api.tickets.query() 

das api Modul enthält diese:

angular.module('myapp.api', [ 
    'ngResource' 
]) 

.factory('api', function($resource, applicationsService) { 

    function fetchAppId() { 
    return applicationsService.getCurrentApp(); 
    } 

    return { 
    tickets: $resource('tickets', { 
     applicationId: fetchAppId 
    }), 
    ... 
    } 

applicationsService.getCurrentApp() macht einen $ http Aufruf selbst. So können Sie vielleicht das Problem sehen - dieser Aufruf wurde möglicherweise nicht durch die Zeit behoben, die fetchAppId() zurückgibt.

Wie kann ich das umgehen?

Antwort

6

Lets Daten sagen, die von applicationsService von Asynchron Weg zurück ist:

var data = [ 
    { 
     "PreAlertInventory": "5.000000", 
     "SharesInInventory": "3.000000", 
     "TotalSharesSold": "2.000000" 
    } 

und applicationsService Fabrik Renditen versprechen:

.factory('applicationsService', ['$resource','$q', function($resource, $q) { 
    var data = [ 
    { 
     "PreAlertInventory": "5.000000", 
     "SharesInInventory": "3.000000", 
     "TotalSharesSold": "2.000000" 
    } 
    ]; 

     var factory = { 
      getCurrentApp: function() { 
       var deferred = $q.defer(); 

       deferred.resolve(data); 

       return deferred.promise; 
      } 
     } 
     return factory; 
}]); 

Ich würde api.tickets() einfach anrufen

$scope.data = api.tickets(); 

aber unser api Service wird wie folgt aussehen:

.factory('api', function($resource, applicationsService,$q, $timeout) { 

    function fetchAppId() {  
     return applicationsService.getCurrentApp(); 
    } 

    return { 
tickets: function() { 
     var deferred=$q.defer(); 
     fetchAppId().then(function(data) { // promise callback 
      $timeout(function(){   // added dummy timeout to simulate delay 
        deferred.resolve(data);  
       }, 3000);      
     }); 
     return deferred.promise; 
    } 
    } 
}); 

Demo Fiddle

+0

Bingo, danke Maxim, das hat wie ein Zauber funktioniert. Schätze die Geige und das Detail :) –

+0

Ich denke, es funktioniert, weil Versprechen in $ scopes auf den $ apply() Zyklus warten, um zu beenden. In der Dokumentation heißt es: "$ q ist mit dem $ rootScope.Scope Scope Modellbeobachtungsmechanismus in eckig integriert, was eine schnellere Verbreitung der Auflösung oder Ablehnung in Ihre Modelle und die Vermeidung unnötiger Browser-Repaints bedeutet, was zu einer flackernden Benutzeroberfläche führen würde." – Plap

+0

Wenn jemand $ Ressource für eine Anfrage verwendet, dann müssen wir $ promise fetchAppId(). $ Versprechen.then (Funktion (Daten) {----}); –

4

Sie müssen ein Versprechen selbst erstellen.

.factory('api', function($resource, applicationsService,$q) { 

    function fetchAppId() { 
    return applicationsService.getCurrentApp(); 
    } 

    return { 
    tickets: function() { 
     var defer=$q.defer(); 
     fetchAppId().then(function(data) { 
      var appId=data; 
      $resource('tickets', {applicationId: appId}) 
       .then(function(data) { 
         defer.resolve(data); 
       }) 
     } 
     return defer.promise; 
    } 
    } 
1

Wenn Sie einen Winkel Ressource warten wollen ($resource) vor einer Routenänderung gelöst werden, man dann‘ Ich muss die $promise zurückgeben.

$routeProvider.when('/tickets', { 
    resolve: { 
     'tickets': function ('Ticket') { 
      // do this to resolve the async call prior to controller load 
      return Ticket.query().$promise; 

      // this will resolve 'tickets' during/after controller load 
      return Ticket.query(); 
     } 
    }, 
    controller: ... 
});