2014-09-17 15 views
11

Ho un servizio che sta effettuando una richiesta AJAX al backendCome rendere regolatore attesa per la promessa di risolvere dal servizio angolare

Servizio:

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

Voglio che il mio servizio gestisca la funzione ".then" invece di doverla gestire nel mio controller, e voglio essere in grado di far agire il mio controller su quei dati DAL servizio, dopo la promessa all'interno di il servizio è stato risolto.

Fondamentalmente, io voglio essere in grado di accedere ai dati in questo modo:

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

Con la risoluzione della promessa di essere gestito all'interno del servizio stesso.

È possibile? O è l'unico modo in cui posso accedere alla risoluzione di quella promessa è al di fuori del servizio?

risposta

-1

si può passare il $ portata in GetCompanies e impostare $ scope.Companies ai dati nel servizio

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

} 

Bisogna stare attenti a l'ordine in cui si quindi utilizzare i dati. Questa è una delle ragioni alla base della promessa di iniziare.

+0

Anche questo è possibile, è considerato una cattiva pratica. Non riesco a capire perché ad Axschech non piace l'approccio originale – ABOS

+0

@ABOS l'idea è di mantenere i dati (e il loro stato) nel servizio, non nel controller. L'esempio originale e questo entrambi fanno l'opposto. L'assegnazione dei dati all'ambito del controller mette lo stato nelle mani del controllore e non nel servizio. – Axschech

+1

Vedo il tuo punto ora. Ma qual è lo scopo di mantenere i dati in servizio, per condividere i dati? Non lo farei nemmeno in questo caso. Preferirei memorizzare i dati sul controller e se desidero condividere i dati/mettere i dati in servizio, chiamo semplicemente il metodo setSharedData (sharedData) del servizio. Questo rende il codice di servizio più testabile e riutilizzabile – ABOS

4

Se invece si è interessati a gestire la risposta del $http nel servizio stesso, è possibile aggiungere una funzione then al servizio dove si fa più l'elaborazione allora return da quella funzione then, in questo modo:

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

Ma avrai ancora una promessa nel controllore, ma ciò che ritorni sarà già stato gestito nel servizio.

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

Spiacente, non vedo come questo sia diverso dal mio post originale, è solo un po 'di sintassi diversa. – Axschech

+0

No, non è solo una sintassi diversa. La funzione 'then' nel servizio verrà eseguita prima della funzione' then' nel controller, dando la possibilità di elaborare la risposta prima che il controllore possa accedervi. –

+1

Giusto ma sfortunatamente devo ancora accedervi tramite il controller all'interno di una promessa. Questo è quello che sto cercando di evitare. È un po 'la metà della soluzione. – Axschech

3

Non c'è alcun problema per raggiungere questo obiettivo!

La cosa principale da tenere a mente è che devi mantenere lo stesso riferimento all'oggetto (e negli array di javascript sono oggetti) nel tuo servizio.

qui è la nostra semplice HTML:

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

Qui è la nostra implementazione del servizio:

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

E infine il controller come si voleva:

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

Spiegazioni

Come detto sopra, il trucco è mantenere il riferimento tra il servizio e il controller. Una volta rispettato questo, è possibile vincolare completamente l'ambito del controller su una proprietà pubblica del servizio.

Here a fiddle that wraps it up.

Nei commenti del codice si può provare a rimuovere il commento il pezzo che non funziona e si vedrà come il regolatore sta perdendo il riferimento. In effetti il ​​controller manterrà un riferimento al vecchio array mentre il servizio cambierà il nuovo.

Un'ultima cosa importante: tenere presente che il timeout $ sta attivando $ apply() sul rootSCope. Questo è il motivo per cui il nostro ambito di controllo si sta aggiornando "da solo". Senza di esso, e se provi a sostituirlo con un normale setTimeout() vedrai che il controller non sta aggiornando l'elenco delle aziende. Per risolvere questo è possibile:

  • non fare nulla se i dati vengono recuperati con $ http come chiama un $ applicare in caso di successo
  • avvolgervi tradurrà in un $ timeout (..., 0);
  • iniettare $ rootSCope nel servizio e chiamare $ applicare() su di esso quando l'operazione asincrona viene eseguita
  • nel controller aggiungere un $ ambito. $ Applicare() sulle getCompanies() promettere successo

Spero che questo aiuti!

+0

Vedere [Perché i metodi di successo/errore $ http angolari sono deprecati? Rimosso dalla v1.6?] (Http://stackoverflow.com/a/35331339/5535245). – georgeawg

+0

Vedi anche [Qual è la promessa esplicita di costruzione antipattern e come posso evitarlo?] (Http://stackoverflow.com/a/25569299/5535245). – georgeawg

+0

@georgeawg Qual è il tuo punto? – Piou

Problemi correlati