1

I am sure this is a configuration error, but not sure how to get round it correctly with angular.

I have my states setup like so

$stateProvider
    .state('app', {
        url: '',
        abstract: true,
        templateProvider: ['$templateCache', function ($templateCache) {
            return $templateCache.get('app/main/main.html');
        }],
        controller: 'MainController',
        resolve: {
            Pages: ['PageFactory', function (PageFactory) {
                return PageFactory.getAll();
            }]
        }

    })
    .state('app.home', {
        url: '/home',
        views: {
            'content@app': {
                templateProvider: ['$templateCache', function ($templateCache) {
                    return $templateCache.get('app/page/page.html');
                }],
                controller: 'PageController'
            }
        },
        resolve: {
            Page: ['$stateParams', 'PageFactory', function ($stateParams, PageFactory) {
                return PageFactory.get($stateParams.id);
            }],
            ModuleData: function () {
                return {};
            },
            Form: function () {
                return {};
            }
        }
    });

Now my problem is that if PageFactory.get($stateParams.id) fails, then the page is reloaded, and reloaded and reloaded.

Here is a sample from PageFactory, which as you can see returns a promise

angular.module('app').factory('PageFactory', ['$http', '$q', function ($http, $q) {

    var urlBase = 'api/page';
    var factory = {};

    factory.getAll = function () {
        var $defer = $q.defer();

        $http.get(urlBase)
            .success(function (data) {
                $defer.resolve(data);
            })
            .error(function (error) {
                $defer.reject(error);
            });

        return $defer.promise;
    };

    factory.get = function (id) {
        var $defer = $q.defer();

        $http.get(urlBase + '/' + id)
            .success(function (data) {
                $defer.resolve(data);
            })
            .error(function (error) {
                $defer.reject(error);
            });

        return $defer.promise;
    };

}]);

It is possible to restrict the number of times the resolve is attempted, or should i have set this up differently in the first place?

I noticed this when moving the site from 1 place to another and needed to specify a base href in my index.html page. Because the $http was trying to connect to a url that didnt exist, it just kept on trying and trying and trying, which if someone left it would harn our web servers performance.

My state app is my route state (abstract state) and the user defaults to app.home uponing entering the site. I guess this is why it just keeps retrying the resolve?

2 Answers 2

1

We also had infinite loops when there were errors in resolves, so we ended up having more logic in the $stateChangeError event handler. Since we have this, we had no more troubles with loops.

See how we check where we were trying to go to and if we failed while going to a home state, we do not try again and redirect to a simple error state instead.

Here our example, this is setup in our main module's run method:

        $rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {

            console.log('Error on StateChange from: "' + (fromState && fromState.name) + '" to:  "'+ toState.name + '", err:' + error.message + ", code: " + error.status);

            if(error.status === 401) { // Unauthorized

                $state.go('signin.content');

            } else if (error.status === 503) {
                // the backend is down for maintenance, we stay on the page
                // a message is shown to the user automatically by the error interceptor
                event.preventDefault();
            } else {

                $rootScope.$emit('clientmsg:error', error);
                console.log('Stack: ' + error.stack);

                // check if we tried to go to a home state, then we cannot redirect again to the same
                // homestate, because that would lead to a loop
                if (toState.name === 'home') {
                    return $state.go('error');
                } else {
                     return $state.go('home');
                }

            }

        });
Sign up to request clarification or add additional context in comments.

Comments

0

The common way to use resolve with promises is to use $q.defer()

Pages: ['PageFactory', '$q', function (PageFactory, $q) {

          var deffered = $q.defer();
          PageFactory.getAll()
            .success(function(data) {
               deffered.resolve(data);
            })
            .error(function(data) {
               deffered.reject();
            })

          return deferred.promise;
        }]

This will reject the the state change if it fails, or you can do whatever when it fails. And it passes the data through if it succeeds.

Also see this post about the same thing.

Angular ui-router get asynchronous data with resolve

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.