2014-09-17 4 views
11

Ich habe einen Dienst, derWie Controller Wartezeit zu machen für Versprechen von Winkel Service lösen zu

Dienst eine AJAX-Anforderung an das Backend macht:

function GetCompaniesService(options) 
    { 
     this.url = '/company'; 
     this.Companies = undefined; 
     this.CompaniesPromise = $http.get(this.url); 

    } 

Controller:

var CompaniesOb = new GetCompanies(); 
CompaniesOb.CompaniesPromise.then(function(data){ 
    $scope.Companies = data; 
}); 

Ich möchte, dass mein Dienst die ".then" -Funktion übernimmt, anstatt sie in meinem Controller zu handhaben, und ich möchte, dass mein Controller auf diese Daten vom Dienst reagiert, nach dem Versprechen innerhalb von t Der Service wurde behoben.

Grundsätzlich möchte ich wie so auf die Daten zugreifen können:

var CompaniesOb = new GetCompanies(); 
$scope.Companies = CompaniesOb.Companies; 

Mit der Auflösung des Versprechens innerhalb des Dienstes selbst gehandhabt wird.

Ist das möglich? Oder ist der einzige Weg, auf den ich zugreifen kann, die Auflösung des Versprechens von außerhalb des Dienstes?

Antwort

-1

Sie können die $ scope in GetCompanies Pass und $ scope.Companies auf die Daten in den Dienst

function GetCompaniesService(options,scope) 
{ 
    this.url = '/company'; 
    this.Companies = undefined; 
    this.CompaniesPromise = $http.get(this.url).then(function(res) { 
     scope.Companies = res; 
    }); 

} 

Sie müssen vorsichtig sein, über die Reihenfolge, in der dann die Daten verwenden gesetzt. Das ist der Grund für ein Versprechen, damit zu beginnen.

+0

Auch das ist möglich, es gilt als schlechte Praxis. Ich kann nicht herausfinden, warum Axschech den ursprünglichen Ansatz nicht mag – ABOS

+0

@ABOS Die Idee ist, die Daten (und ihren Zustand) im Dienst zu halten, nicht im Controller. Das ursprüngliche Beispiel, und dies tun beide das Gegenteil. Durch die Zuweisung der Daten zum Bereich des Controllers wird der Status in die Hände des Controllers und nicht in den Dienst gestellt. – Axschech

+1

Ich sehe Ihren Punkt jetzt. Aber was ist der Zweck, Daten im Dienst zu halten, um Daten zu teilen? Ich würde es nicht tun, auch das ist der Fall. Ich würde lieber Daten auf dem Controller speichern und wenn ich Daten teilen/Daten auf den Dienst legen möchte, rufe ich einfach die setSharedData (sharedData) -Methode des Dienstes auf. Dies macht Service-Code mehr testbar und wiederverwendbar – ABOS

4

Wenn alles, was Sie wollen, ist die Antwort von $http in den Dienst selbst zu behandeln, können Sie eine then Funktion zum Dienst hinzufügen, wo Sie weitere Verarbeitung tun dann return aus dieser then Funktion, wie folgt aus:

function GetCompaniesService(options) { 
    this.url = '/company'; 
    this.Companies = undefined; 
    this.CompaniesPromise = $http.get(this.url).then(function(response) { 
    /* handle response then */ 
    return response 
    }) 
} 

Aber Sie haben immer noch ein Versprechen in der Steuerung, aber was Sie zurück bekommen, wird bereits im Service behandelt.

var CompaniesOb = new GetCompanies(); 
CompaniesOb.CompaniesPromise.then(function(dataAlreadyHandledInService) { 
    $scope.Companies = dataAlreadyHandledInService; 
}); 
+0

Tut mir leid, ich sehe nicht, wie das von meinem ursprünglichen Post anders ist, es ist nur ein bisschen andere Syntax. – Axschech

+0

Nein, es ist nicht nur eine andere Syntax. Die "Then" -Funktion im Service wird vor der "Then" -Funktion im Controller ausgeführt, sodass Sie die Antwort bearbeiten können, bevor der Controller darauf zugreifen kann. –

+1

Richtig aber leider muss ich noch über den Controller darauf zugreifen. Das versuche ich zu vermeiden. Es ist eine Art halbe Lösung. – Axschech

3

Es gibt kein Problem, das zu erreichen!

Die wichtigste Sache, die Sie beachten müssen, ist, dass Sie die gleiche Objektreferenz (und in Javascript Arrays sind Objekte) in Ihrem Dienst halten müssen.

hier ist unser einfaches HTML:

<div ng-controller = "companiesCtrl"> 
    <ul ng-repeat="company in companies"> 
    <li>{{company}}</li> 
    </ul> 
</div> 

Hier unsere Service-Implementierung ist:

serviceDataCaching.service('companiesSrv', ['$timeout', function($timeout){ 
    var self = this; 

    var httpResult = [ 
    'company 1', 
    'company 2', 
    'company 3' 
    ]; 

    this.companies = ['preloaded company']; 
    this.getCompanies = function() { 
    // we simulate an async operation 
    return $timeout(function(){ 
     // keep the array object reference!! 
     self.companies.splice(0, self.companies.length); 

     // if you use the following code: 
     // self.companies = []; 
     // the controller will loose the reference to the array object as we are creating an new one 
     // as a result it will no longer get the changes made here! 
     for(var i=0; i< httpResult.length; i++){ 
     self.companies.push(httpResult[i]); 
     } 
     return self.companies; 
    }, 3000);      
}}]); 

Und schließlich die Steuerung wie man es wollte:

serviceDataCaching.controller('companiesCtrl', function ($scope, companiesSrv) { 
    $scope.companies = companiesSrv.companies; 
    companiesSrv.getCompanies(); 
}); 

Erläuterungen

Wie oben gesagt, besteht der Trick darin, den Bezug zwischen dem Dienst und dem Controller beizubehalten. Sobald Sie dies respektieren, können Sie Ihren Controller-Bereich vollständig an eine öffentliche Eigenschaft Ihres Service binden.

Here a fiddle that wraps it up.

In den Kommentaren des Codes können Sie uncomment das Stück versuchen, das nicht funktioniert, und Sie werden sehen, wie die Steuerung die Referenz verliert. Tatsächlich wird der Controller weiterhin einen Verweis auf das alte Array haben, während der Service den neuen ändern wird.

Eine letzte wichtige Sache: Denken Sie daran, dass $ Timeout ein $ apply() auf dem rootSCope auslöst. Aus diesem Grund erfrischt unser Controller-Umfang "alleine". Ohne es, und wenn Sie versuchen, es mit einem normalen setTimeout() zu ersetzen, werden Sie sehen, dass der Controller die Firmenliste nicht aktualisiert. Um dies zu umgehen können Sie:

  • nichts tun, wenn Sie Ihre Daten mit $ http abgerufen wird, wie es ein $ gelten auf Erfolg
  • wickeln ruft Sie in einem $ Timeout führen (..., 0);
  • inject $ rootSCope im Dienst und rufe $ apply() auf es, wenn die asynchrone Operation
  • in der Steuerung einen $ Rahmen hinzufügen erfolgt. $ Apply() auf dem getCompanies() verspricht Erfolg

Hoffe, das hilft!

+0

Siehe [Warum sind angulare $ http-Erfolgs-/Fehlermethoden veraltet? Aus v1.6 entfernt?] (Http://stackoverflow.com/a/35331339/5535245). – georgeawg

+0

Siehe auch [Was ist das explizite Versprechen Bau Antipattern und wie vermeide ich es?] (Http://stackoverflow.com/a/25569299/5535245). – georgeawg

+0

@georgeawg Was ist dein Standpunkt? – Piou

Verwandte Themen