Search code examples
javascriptangularjsangularjs-scopeangularjs-serviceangularjs-http

AngularJS, how do I use a service to capture HTTP data and bind it to my controller?


I have an API call that's working great, but I'd like to use it on several controllers so I moved it to it's own service. I'm running into what looks like a classic Scope issue or a misunderstanding of Angular's digest cycle.

'use strict';
myApp.factory('Stuff',['$http', function ($http) {
  var Stuff = {};
  Stuff.data = {};
  Stuff.api = 'http://localhost:8080/api/';
  Stuff.getStuff = function() {
    var http_stuff_config = {
      method: 'GET',
      url: Stuff.api + 'stuff/'
    };
    $http(http_stuff_config).then(function successCallback(response) {
      Stuff.data = (response.data);
      console.log(Stuff.data); // Returns populated object. 
    },function errorCallback(response) {
      console.log(response.statusText);
    });
  };
  Stuff.getStuff();
  console.log(Stuff.data); // Returns empty object.
  return Stuff;
}]);

myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
  $scope.stuff = Stuff;
  console.log($scope.stuff.data); // Returns empty object.
  $scope.stuff.getJobs();
  console.log($scope.stuff.data); // Returns empty object.
}]);

Here's the big clue. The essential output of above, in order is...

  1. empty object (in service after calling method)
  2. empty object (in controller before calling method)
  3. empty object (in controller after calling method)
  4. populated object (in method execution from service)
  5. populated object (in method execution from controller)

So somewhere between the scope of the getStuff() method and Angular's order of operations, I'm doing something remarkably foolish. Thank you in advance.


Solution

  • You need to add returns on your service, or else the promise will not be returned to the controller. It is not good practice to just store the returns in your services AND NOT return the result to the controller.

    This is considered bad practice because, any time you update the data on the service everyone will need to apply $scope.$watch to the service to look for updates. This can be very expensive in large scale apps.

    The best Idea is to return the data to the calling controller (if you do not need to cache it, this we can talk about later) and let the controller access it via the promise service.getthing().then(function(result){});

    myApp.factory('Stuff',['$http', function ($http) {
      var Stuff = {};
      Stuff.data = {};
      Stuff.api = 'http://localhost:8080/api/';
      Stuff.getStuff = function() {
        var http_stuff_config = {
          method: 'GET',
          url: Stuff.api + 'stuff/'
        };
        return $http(http_stuff_config).then(function successCallback(response) {
          return response.data;
          console.log(Stuff.data); // Returns populated object. 
        },function errorCallback(response) {
          console.log(response.statusText);
        });
      };
      Stuff.getStuff();
      console.log(Stuff.data); // Returns empty object.
      return Stuff;
    }]);
    
    
    
    
    myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
      $scope.stuff = Stuff;
      console.log($scope.stuff.data); // Returns empty object.
      $scope.stuff.getJobs().then(function(result) {$scope.stuff = result; console.log(result);});
      console.log($scope.stuff.data); // Returns empty object.
    }]);