Processing $http response in service

后端 未结 12 1628
半阙折子戏
半阙折子戏 2020-11-22 03:36

I recently posted a detailed description of the issue I am facing here at SO. As I couldn\'t send an actual $http request, I used timeout to simulate asynchrono

相关标签:
12条回答
  • 2020-11-22 04:11

    tosh shimayama have a solution but you can simplify a lot if you use the fact that $http returns promises and that promises can return a value:

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

    A little demonstration in coffeescript: http://plunker.no.de/edit/ksnErx?live=preview

    Your plunker updated with my method: http://plnkr.co/edit/mwSZGK?p=preview

    0 讨论(0)
  • 2020-11-22 04:15

    Related to this I went through a similar problem, but not with get or post made by Angular but with an extension made by a 3rd party (in my case Chrome Extension).
    The problem that I faced is that the Chrome Extension won't return then() so I was unable to do it the way in the solution above but the result is still Asynchronous.
    So my solution is to create a service and to proceed to a callback

    app.service('cookieInfoService', function() {
        this.getInfo = function(callback) {
            var model = {};
            chrome.cookies.get({url:serverUrl, name:'userId'}, function (response) {
                model.response= response;
                callback(model);
            });
        };
    });
    

    Then in my controller

    app.controller("MyCtrl", function ($scope, cookieInfoService) {
        cookieInfoService.getInfo(function (info) {
            console.log(info);
        });
    });
    

    Hope this can help others getting the same issue.

    0 讨论(0)
  • 2020-11-22 04:17

    I had the same problem, but when I was surfing on the internet I understood that $http return back by default a promise, then I could use it with "then" after return the "data". look at the code:

     app.service('myService', function($http) {
           this.getData = function(){
             var myResponseData = $http.get('test.json').then(function (response) {
                console.log(response);.
                return response.data;
              });
             return myResponseData;
    
           }
    });    
     app.controller('MainCtrl', function( myService, $scope) {
          // Call the getData and set the response "data" in your scope.  
          myService.getData.then(function(myReponseData) {
            $scope.data = myReponseData;
          });
     });
    
    0 讨论(0)
  • 2020-11-22 04:18

    Please try the below Code

    You can split the controller (PageCtrl) and service (dataService)

    'use strict';
    (function () {
        angular.module('myApp')
            .controller('pageContl', ['$scope', 'dataService', PageContl])
            .service('dataService', ['$q', '$http', DataService]);
        function DataService($q, $http){
            this.$q = $q;
            this.$http = $http;
            //... blob blob 
        }
        DataService.prototype = {
            getSearchData: function () {
                var deferred = this.$q.defer(); //initiating promise
                this.$http({
                    method: 'POST',//GET
                    url: 'test.json',
                    headers: { 'Content-Type': 'application/json' }
                }).then(function(result) {
                    deferred.resolve(result.data);
                },function (error) {
                    deferred.reject(error);
                });
                return deferred.promise;
            },
            getABCDATA: function () {
    
            }
        };
        function PageContl($scope, dataService) {
            this.$scope = $scope;
            this.dataService = dataService; //injecting service Dependency in ctrl
            this.pageData = {}; //or [];
        }
        PageContl.prototype = {
             searchData: function () {
                 var self = this; //we can't access 'this' of parent fn from callback or inner function, that's why assigning in temp variable
                 this.dataService.getSearchData().then(function (data) {
                     self.searchData = data;
                 });
             }
        }
    }());

    0 讨论(0)
  • 2020-11-22 04:20

    A much better way I think would be something like this:

    Service:

    app.service('FruitsManager',function($q){
    
        function getAllFruits(){
            var deferred = $q.defer();
    
            ...
    
            // somewhere here use: deferred.resolve(awesomeFruits);
    
            ...
    
            return deferred.promise;
        }
    
        return{
            getAllFruits:getAllFruits
        }
    
    });
    

    And in the controller you can simply use:

    $scope.fruits = FruitsManager.getAllFruits();
    

    Angular will automatically put the resolved awesomeFruits into the $scope.fruits.

    0 讨论(0)
  • 2020-11-22 04:25

    I really don't like the fact that, because of the "promise" way of doing things, the consumer of the service that uses $http has to "know" about how to unpack the response.

    I just want to call something and get the data out, similar to the old $scope.items = Data.getData(); way, which is now deprecated.

    I tried for a while and didn't come up with a perfect solution, but here's my best shot (Plunker). It may be useful to someone.

    app.factory('myService', function($http) {
      var _data;  // cache data rather than promise
      var myService = {};
    
      myService.getData = function(obj) { 
        if(!_data) {
          $http.get('test.json').then(function(result){
            _data = result.data;
            console.log(_data);  // prove that it executes once
            angular.extend(obj, _data);
          }); 
        } else {  
          angular.extend(obj, _data);
        }
      };
    
      return myService;
    }); 
    

    Then controller:

    app.controller('MainCtrl', function( myService,$scope) {
      $scope.clearData = function() {
        $scope.data = Object.create(null);
      };
      $scope.getData = function() {
        $scope.clearData();  // also important: need to prepare input to getData as an object
        myService.getData($scope.data); // **important bit** pass in object you want to augment
      };
    });
    

    Flaws I can already spot are

    • You have to pass in the object which you want the data added to, which isn't an intuitive or common pattern in Angular
    • getData can only accept the obj parameter in the form of an object (although it could also accept an array), which won't be a problem for many applications, but it's a sore limitation
    • You have to prepare the input object $scope.data with = {} to make it an object (essentially what $scope.clearData() does above), or = [] for an array, or it won't work (we're already having to assume something about what data is coming). I tried to do this preparation step IN getData, but no luck.

    Nevertheless, it provides a pattern which removes controller "promise unwrap" boilerplate, and might be useful in cases when you want to use certain data obtained from $http in more than one place while keeping it DRY.

    0 讨论(0)
提交回复
热议问题