web-dev-qa-db-fra.com

Comment faire pour que le contrôleur attende que la promesse soit résolue à partir du service angular

J'ai un service qui fait une demande AJAX au backend

Un service:

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

    }

Manette:

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

Je veux que mon service gère la fonction ".then" au lieu de devoir la gérer dans mon contrôleur, et je veux pouvoir faire en sorte que mon contrôleur agisse sur ces données du service, après que la promesse à l'intérieur du service a été résolue.

Fondamentalement, je veux pouvoir accéder aux données comme ceci:

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

La résolution de la promesse étant gérée à l'intérieur du service lui-même.

Est-ce possible? Ou est-ce que la seule façon d'accéder à la résolution de cette promesse est de l'extérieur du service?

11
Axschech

Si tout ce que vous voulez, c'est gérer la réponse de $http dans le service lui-même, vous pouvez ajouter une fonction then au service où vous effectuez plus de traitement que return à partir de cette fonction then, comme ceci:

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

Mais vous devrez toujours utiliser une promesse dans le contrôleur, mais ce que vous récupérez aura déjà été traité dans le service.

var CompaniesOb = new GetCompanies();
CompaniesOb.CompaniesPromise.then(function(dataAlreadyHandledInService) {
  $scope.Companies = dataAlreadyHandledInService;
});
4
M.K. Safi

Il n'y a aucun problème pour y parvenir!

La principale chose que vous devez garder à l'esprit est que vous devez conserver la même référence d'objet (et dans les tableaux javascript sont des objets) dans votre service.

voici notre HTML simple:

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

Voici notre implémentation de service:

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

Et enfin le contrôleur comme vous le vouliez:

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

Explications

Comme indiqué ci-dessus, l'astuce consiste à conserver la référence entre le service et le contrôleur. Une fois que vous respectez cela, vous pouvez lier totalement la portée de votre contrôleur sur une propriété publique de votre service.

Voici un violon qui l'enveloppe.

Dans les commentaires du code, vous pouvez essayer de décommenter la pièce qui ne fonctionne pas et vous verrez comment le contrôleur perd la référence. En fait, le contrôleur conservera une référence à l'ancienne baie tandis que le service changera la nouvelle.

Une dernière chose importante: gardez à l'esprit que le timeout $ déclenche un $ apply () sur le rootSCope. C'est pourquoi la portée de notre contrôleur est rafraîchissante "seule". Sans cela, et si vous essayez de le remplacer par un setTimeout () normal, vous verrez que le contrôleur ne met pas à jour la liste des sociétés. Pour contourner ce problème, vous pouvez:

  • ne faites rien si vos données sont récupérées avec $ http car il appelle un $ apply en cas de succès
  • envelopper vous entraînez un timeout $ (..., 0);
  • injectez $ rootSCope dans le service et appelez $ apply () dessus lorsque l'opération asynchrone est terminée
  • dans le contrôleur, ajoutez un $ scope. $ apply () sur la promesse de getCompanies ()

J'espère que cela t'aides!

3
Piou