2

In my $routeProvider I have a resolve property to get data from an API before I instantiate my controller. Why is it when I use the $q with the $http service, I can pass the data to my controller. Aren't they both doing the same thing?

Here is my original approach where the data wasn't able to get passed to the controller:

AccountService.js

app.factory('AccountService', ['$http', '$q', function ($http, $q) {
    return {
        GetAccounts: function () {
            return $http.get('api/Account/GetAccounts')
            .then(function success(response) {
                return response;
            }, function error(response) {
                ̶r̶e̶t̶u̶r̶n̶ throw console.log("Oops!");
            });
        },
    };
}]);

To pass the data into the controller I change up the GetAccounts to this:

app.factory('AccountService', ['$http', '$q', function ($http, $q) {
    return {
        GetAccounts: function () {
            var deferred = $q.defer();
            $http.get('api/Account/GetAccounts')
            .then(function (data) {
                deferred.resolve(data.data);
            })
            .catch(function (response) {
                deferred.reject(response);
            })

            return deferred.promise;
        },
    };
}]);

route.js

app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/users', {
        template: '<admin accounts="$resolve.accounts"></admin>',
        resolve: {
            accounts: function (AccountService) {
                return AccountService.GetAccounts()
                    .then(function (data) {
                        return data;
                    })
            }
        }
    })
}]);
georgeawg
  • 48,608
  • 13
  • 72
  • 95
Ron T
  • 397
  • 1
  • 4
  • 22
  • your first example is returning the `response`, while your second example is returning `response.data` (though you renamed it to `data.data`) – Claies Apr 09 '17 at 02:21
  • @Claies got it, thanks for pointing that out. Now they both work – Ron T Apr 09 '17 at 03:43
  • There is no need to manufacture a promise with `$q.defer` as the [$http service](https://docs.angularjs.org/api/ng/service/$http) already returns a promise. See [Is this a “Deferred Antipattern”?](http://stackoverflow.com/questions/30750207/is-this-a-deferred-antipattern). – georgeawg Apr 09 '17 at 06:46

2 Answers2

3

$q is Angulars wrapper for promises. $http returns a promise directly so whether you create a new promise with a new $q or $http directly, they are the same

g3ctong
  • 86
  • 4
0

So essentially you dont have to do what you do in AccountService, only this is needed:

app.factory('AccountService', ['$http', function ($http) {
    return {
        GetAccounts: function () {

            return $http.get('api/Account/GetAccounts')
            .then(function (data) {
                return data.data;
            })
        },
    };
}]);

I would save the .catch() for your resolve to handle and maybe wrap the error in a nice error construct unless your backend already does that.

app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/users', {
        template: '<admin accounts="$resolve.accounts"></admin>',
        resolve: {
            accounts: function (AccountService) {
                return AccountService.GetAccounts()
                    .catch( function(err) { ̶r̶e̶t̶u̶r̶n̶ throw new BusinessError( err ) } )
            }
        }
    })
}]);

or let the calling controller/component handle it, its an architecture decision.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Chris Noring
  • 471
  • 3
  • 9