Search code examples
javascriptangularjsasynchronousdeferred

Using AngularJS $q promises in helper factory


I'm trying to wrap by head around when to use $q in AngularJS. I've been using it in all my services so far so when I call our Web API it works nicely. What I'm trying to do is cut down on all the calls to the API since I need the same data in multiple places and I've just been pinging the API every time I needed the data.

Right now I have a service, which gets the data and a helper file to help with related things about the data.

What I want is to use this helper factory to hold the data that's needed for every body which uses it.

I'm having trouble wrapping my head around assigning the value of data from the helper file if the data hasn't gotten back to me yet when AngularJS runs.

This is what I have so far.

(function() {
  var app = angular.module("Test", []);
  app.service("githubService", function($http, $q) {
    var deferred = $q.defer();

    this.getAccount = function() {
      return $http.get('https://api.github.com/users/JonDoe');
    };
  });

  app.factory("githubHelper", ["githubService", function(githubService) {
    _gitHubInfo = {};

    githubService.getAccount().then(function(data) {
      _gitHubInfo = data;
    });

    return {
      gitHubInfo: _gitHubInfo
    };
  }]);

  app.controller("Dummy", ["$scope", "githubHelper", "githubService", function($scope, githubHelper, githubService) {
    
    // How do I make it work this way?
    $scope.value = githubHelper.gitHubInfo;
    
    // This is what I'm using now
    githubService.getAccount().then(function(data) {
      $scope.value2 = data;
    });
  }]);
})();
.box {
  border: 1px red solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="Test">
  <div ng-controller="Dummy">
    <div class="box">
      {{value}}
    </div>
    <br />
    <div class="box">
      {{value2}}
    </div>
  </div>
</div>

What I want to do is just remove the githubService dependency from the Dummy controller and only have it present in the githubHelper factory so I can remove the dependency on githubService from all my controllers and instead use gitHubHelper.

What do I need to change in Dummy controller to have $scope.value be the data returned from githubService.getAccount()?


Solution

  • I have something like this in my project:

    app.factory("githubHelper", ["githubService", function(githubService) {
        var promise = null;
    
        function getInfo() {
          if (!promise) {
            promise = githubService.getAccount();
          }
          return promise;
        }
    
        return {
          getInfo: getInfo
        };
      }]);
    
    githubHelper.getInfo().then(function(data) {})
    githubHelper.getInfo().then(function(data) {})
    githubHelper.getInfo().then(function(data) {})
    ...