A A
A A

Reputation: 147

AngularJS, How to get resolve value using a factory with $http?

I have declared a state using ui-router and am trying to perform a resolve. However, I cannot return a value in my resolve using a $http in a factory. Below is one way that I've tried.

It appears that the success callback runs too late so that nothing is actually returned inside the resolve. When the success callback does run, it produces the desired result.

...
.state('book', {
    url: '/book',
    abstract: true,
    views: {
        '': { 
            templateUrl: 'templates/book.html',
            controller: bookController
        }
    }
})
.state('book.detail', {
    url: '/{chapter}/{pageName}',
    resolve: {
        pageIdNumber: ['$http','$stateParams', 'myFactory', function($http, $stateParams, myFactory) {
            return myFactory.getPageIdNumberUsingPageName(
                function(response, $stateParams) {return response[0];}, // console.log(response[0]) gives the desired result but nothing is returned. I think this function runs too late.
                function(response) {return response[0];},
                $stateParams.pageName);
            }]
    },
    views: {
        'page@book': { 
             templateUrl: 'templates/page.html',
             controller: pageController
         }
    }
})
...

myFactory.$inject = ['$http'];
function myFactory($http){
    return {
        getPageIdNumberUsingPageName: function (callbackSuccess, callbackError, pageName){
            $http({
                method: 'POST',
                url: 'http://example.com/api/get_page_id.json',
                cache: true,
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                data: 'page_name=' + encodeURIComponent(pageName),
            })
            .success(function (response) {
                callbackSuccess(response);
            })
            .error(function (response) {
                callbackError(response);
            });
        }
    };
}

Upvotes: 1

Views: 872

Answers (1)

A A
A A

Reputation: 147

In the resolve, you must return a promise object - you cannot return a value:

...
.state('book.detail', {
    url: '/{chapter}/{pageName}',
    resolve: {
        pageIdNumber: ['$http','$stateParams', 'myFactory', function($http, $stateParams, myFactory) {
            return $something; // $something must be a promise object and not a value like "2" or "dog".
            }]
    },
...

However, the code provided in the question uses a factory to retrieve a value. We must change the factory so that it retrieves a promise. To do this, we note that the success method returns values and the then method returns a promise:

    function myFactory($http){
        return {
            getPageIdNumberUsingPageName: function (callbackSuccess, callbackError, pageName){
                $http({
                    ...
                })
                .success(function (response) {
                    // response contains values like "2" and/or "dog"
                });
            }
        };
    }

    function myFactory($http){
        return {
            getPageIdNumberUsingPageName: function (callbackSuccess, callbackError, pageName){
                $http({
                    ...
                })
                .then(function (response) {
                    // response contains a promise object that, when eventually fulfilled, will produce values like "2" and/or "dog"
                });
            }
        };

}

So, the factory changes to:

myFactory.$inject = ['$http'];
function myFactory($http){
    return {
        getPageIdNumberUsingPageName: function (pageName){
            return $http({     // notice the "return" here
                method: 'POST',
                url: 'http://example.com/api/get_page_id.json',
                cache: true,
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                data: 'page_name=' + encodeURIComponent(pageName),
            })
            .then(function (response) {
                return response.data[0]; // data[0] contains the value that I want. response is a promise object
            });
        }
    };
}

And the resolve becomes (read the comments in the code):

...
.state('book.detail', {
    url: '/{chapter}/{pageName}',
    resolve: {
        pageIdNumber: ['$http','$stateParams', 'myFactory', function($http, $stateParams, myFactory) {
            return myFactory.getPageIdNumberUsingPageName($stateParams.pageName); // this returns the $http object in the factory; that factory in turn returns the promise object.
            }]
    },
    views: {
        'page@book': { 
             templateUrl: 'templates/page.html',
             controller: pageController
         }
    }
...

Upvotes: 2

Related Questions