2013-08-24 8 views
81

Sto utilizzando alcuni dati provenienti da un servizio RESTful in più pagine. Quindi sto usando fabbriche angolari per questo. Quindi, ho richiesto di ottenere i dati una volta dal server e ogni volta che ottengo i dati con quel servizio definito. Proprio come una variabile globale. Ecco l'esempio:

var myApp = angular.module('myservices', []); 

myApp.factory('myService', function($http) { 
    $http({method:"GET", url:"/my/url"}).success(function(result){ 
     return result; 
    }); 
}); 

Nel mio controller Sto usando questo servizio come:

function myFunction($scope, myService) { 
    $scope.data = myService; 
    console.log("data.name"+$scope.data.name); 
} 

il suo bel lavoro per me come per le mie esigenze. Ma il problema qui è che quando ricarico nella mia pagina web il servizio verrà nuovamente chiamato e richieste per il server. Se tra qualche altra funzione si esegue che dipende dal "servizio definito", si dà l'errore come "qualcosa" non è definito. Quindi voglio aspettare nel mio script fino a quando il servizio non viene caricato. Come lo posso fare? Esiste lo stesso in Angularjs?

risposta

138

È necessario utilizzare le promesse per le operazioni asincrone in cui non si sa quando sarà completato. Una promessa "rappresenta un'operazione che non è ancora stata completata, ma è prevista per il futuro". (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise)

un esempio di implementazione sarebbe come:

myApp.factory('myService', function($http) { 

    var getData = function() { 

     // Angular $http() and then() both return promises themselves 
     return $http({method:"GET", url:"/my/url"}).then(function(result){ 

      // What we return here is the data that will be accessible 
      // to us after the promise resolves 
      return result.data; 
     }); 
    }; 


    return { getData: getData }; 
}); 


function myFunction($scope, myService) { 
    var myDataPromise = myService.getData(); 
    myDataPromise.then(function(result) { 

     // this is only run after getData() resolves 
     $scope.data = result; 
     console.log("data.name"+$scope.data.name); 
    }); 
} 

Edit: Per quanto riguarda Sujoys commento che che cosa devo fare in modo che chiamata myFuction() non tornerà fino .then() la funzione termina l'esecuzione.

function myFunction($scope, myService) { 
    var myDataPromise = myService.getData(); 
    myDataPromise.then(function(result) { 
     $scope.data = result; 
     console.log("data.name"+$scope.data.name); 
    }); 
    console.log("This will get printed before data.name inside then. And I don't want that."); 
} 

Bene, supponiamo la chiamata a getData() ci sono voluti 10 secondi per completare. Se la funzione non restituiva nulla in quel momento, sarebbe effettivamente diventato normale codice sincrono e avrebbe bloccato il browser fino al completamento.

Con la promessa che ritorna istantaneamente, il browser è libero di continuare con altro codice nel frattempo. Una volta che la promessa si risolve/fallisce, viene attivata la chiamata then(). Quindi ha molto più senso in questo modo, anche se potrebbe rendere il flusso del codice un po 'più complesso (la complessità è un problema comune di programmazione asincrona/parallela in generale!)

+2

Questo ha risolto il mio problema !!! Per chiunque altro, disponevo di un menu a discesa che richiedeva i dati della chiamata ajax, quindi, una volta creato l'ambito, i dati non erano disponibili. Con questo differimento, l'ambito può essere assegnato per avere i dati provenienti dalla chiamata Ajax. –

+6

@ mikel: Ho un'altra domanda qui. La tua chiamata a myFuction() tornerà immediatamente ma quella promessa. Cosa devo fare affinché la chiamata a myFuction() non ritorni finché la funzione .then() non termina l'esecuzione. 'function myFunction ($ scope, myService) { var myDataPromise = myService.getData(); myDataPromise.then (funzione (risultato) { $ scope.data = result; console.log ("data.name" + $ scope.data.name); }); console.log ("Questo verrà stampato prima di data.name allora. E non lo voglio."); } ' – Sujoy

12

per le persone nuove a questo voi può anche utilizzare un callback per esempio:

Nel vostro servizio:

.factory('DataHandler',function ($http){ 

    var GetRandomArtists = function(data, callback){ 
    $http.post(URL, data).success(function (response) { 
     callback(response); 
     }); 
    } 
}) 

nel controller:

DataHandler.GetRandomArtists(3, function(response){ 
     $scope.data.random_artists = response; 
    }); 
+0

Ottima soluzione. Stavo pensando su questa stessa linea quando ci stavo guardando. Sono contento che qualcuno l'abbia messo là fuori. – Nate

0

ho avuto lo stesso problema e nessuno se questi ha funzionato per me Ecco cosa ha funzionato anche se ...

app.factory('myService', function($http) { 
    var data = function (value) { 
      return $http.get(value); 
    } 

    return { data: data } 
}); 

e poi la funzione che utilizza è ...

vm.search = function(value) { 

     var recieved_data = myService.data(value); 

     recieved_data.then(
      function(fulfillment){ 
       vm.tags = fulfillment.data; 
      }, function(){ 
       console.log("Server did not send tag data."); 
     }); 
    }; 

Il servizio non è che necessario, ma penso che la sua una buona pratica per l'estensibilità . La maggior parte di ciò che ti servirà per una volontà per qualsiasi altra, specialmente quando usi le API. Comunque spero sia stato utile.

0

FYI, questo sta utilizzando Angularfire in modo che possa variare un po 'per un servizio diverso o altro uso, ma dovrebbe risolvere lo stesso hasse $ http. Ho avuto questo stesso problema, ma la soluzione migliore per me è stata la migliore per combinare tutti i servizi/le fabbriche in un'unica promessa sull'ottica. Su ogni percorso/vista che aveva bisogno di questi servizi/etc da caricare ho messo tutte le funzioni che richiedono caricati i dati all'interno della funzione di controllo ovvero MyFunct() e le principali app.js sulla fuga dopo autenticazione ho messo

myservice.$loaded().then(function() {$rootScope.myservice = myservice;}); 

e nella vista ho appena fatto

ng-if="myservice" ng-init="somevar=myfunct()" 

nel primo/vista padre elemento/involucro in modo che il controllore può eseguire tutto all'interno

myfunct() 

senza preoccuparsi asincrona promesse/ordine/que ue problemi. Spero che aiuti qualcuno con gli stessi problemi che ho avuto.

Problemi correlati