233 votes

Traitement de la réponse $http dans le service

J'ai récemment publié une description détaillée du problème auquel je suis confronté. aquí à SO. Comme je ne pouvais pas envoyer un $http j'ai utilisé le timeout pour simuler un comportement asynchrone. La liaison des données de mon modèle à la vue fonctionne correctement, avec l'aide de @Gloopy.

Maintenant, quand j'utilise $http au lieu de $timeout (testé localement), j'ai pu constater que la requête asynchrone avait réussi et que data est rempli avec la réponse json dans mon service. Mais, ma vue n'est pas mise à jour.

mise à jour de Plunkr aquí

418voto

Pete BD Points 4774

Voici un Plunk qui fait ce que vous voulez : http://plnkr.co/edit/TTlbSv?p=preview

L'idée est de travailler directement avec les promesses et leurs fonctions "then" pour manipuler et accéder aux réponses renvoyées de manière asynchrone.

app.factory('myService', function($http) {
  var myService = {
    async: function() {
      // $http returns a promise, which has a then function, which also returns a promise
      var promise = $http.get('test.json').then(function (response) {
        // The then function here is an opportunity to modify the response
        console.log(response);
        // The return value gets picked up by the then in the controller.
        return response.data;
      });
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  // Call the async method and then do stuff with what is returned inside our own then function
  myService.async().then(function(d) {
    $scope.data = d;
  });
});

Voici une version un peu plus compliquée qui met en cache la requête afin que vous ne la fassiez que la première fois ( http://plnkr.co/edit/2yH1F4IMZlMS8QsV9rHv?p=preview ):

app.factory('myService', function($http) {
  var promise;
  var myService = {
    async: function() {
      if ( !promise ) {
        // $http returns a promise, which has a then function, which also returns a promise
        promise = $http.get('test.json').then(function (response) {
          // The then function here is an opportunity to modify the response
          console.log(response);
          // The return value gets picked up by the then in the controller.
          return response.data;
        });
      }
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  $scope.clearData = function() {
    $scope.data = {};
  };
  $scope.getData = function() {
    // Call the async method and then do stuff with what is returned inside our own then function
    myService.async().then(function(d) {
      $scope.data = d;
    });
  };
});

82voto

allenhwkim Points 6012

Que ce soit simple. C'est aussi simple que

  1. Retourner à promise dans votre service (pas besoin d'utiliser then en service)
  2. Utilice then dans votre contrôleur

Démonstration. http://plnkr.co/edit/cbdG5p?p=preview

var app = angular.module('plunker', []);

app.service('myService', function($http) {
  return {
    async: function() {
      return $http.get('test.json');  //1. this returns promise
    }
  };
});

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function(d) { //2. so you can use .then()
    $scope.data = d;
  });
});

58voto

Tosh Points 13477

Parce qu'il est asynchrone, le $scope est d'obtenir les données avant que l'appel ajax soit terminé.

Vous pourriez utiliser $q dans votre service pour créer promise et le renvoie au contrôleur, et le contrôleur obtient le résultat dans then() appel contre promise .

A votre service,

app.factory('myService', function($http, $q) {
  var deffered = $q.defer();
  var data = [];  
  var myService = {};

  myService.async = function() {
    $http.get('test.json')
    .success(function (d) {
      data = d;
      console.log(d);
      deffered.resolve();
    });
    return deffered.promise;
  };
  myService.data = function() { return data; };

  return myService;
});

Ensuite, dans votre contrôleur :

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function() {
    $scope.data = myService.data();
  });
});

23voto

Guillaume86 Points 7812

Tosh shimayama a une solution mais vous pouvez simplifier beaucoup si vous utilisez le fait que $http retourne des promesses et que les promesses peuvent retourner une valeur :

app.factory('myService', function($http, $q) {
  myService.async = function() {
    return $http.get('test.json')
    .then(function (response) {
      var data = reponse.data;
      console.log(data);
      return data;
    });
  };

  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  $scope.asyncData = myService.async();
  $scope.$watch('asyncData', function(asyncData) {
    if(angular.isDefined(asyncData)) {
      // Do something with the returned data, angular handle promises fine, you don't have to reassign the value to the scope if you just want to use it with angular directives
    }
  });

});

Une petite démonstration en coffeescript : http://plunker.no.de/edit/ksnErx?live=preview

Votre plunker a été mis à jour avec ma méthode : http://plnkr.co/edit/mwSZGK?p=preview

7voto

HasanAboShally Points 2705

Je pense qu'une meilleure méthode serait quelque chose comme ça :

Service :

app.service('FruitsManager',function($q){

    function getAllFruits(){
        var deferred = $q.defer();

        ...

        // somewhere here use: deferred.resolve(awesomeFruits);

        ...

        return deferred.promise;
    }

    return{
        getAllFruits:getAllFruits
    }

});

Et dans le contrôleur, vous pouvez simplement utiliser :

$scope.fruits = FruitsManager.getAllFruits();

Angular placera automatiquement la résolution awesomeFruits dans le $scope.fruits .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X