Defer Angular UI Router $stateChangeStart until server authorization response receieved

北战南征 提交于 2019-11-29 03:44:38

I'd create a function in your Auth service that returns a promise. Later, resolve (authorized) or reject (not authrized) that deferred. Then use it on the resolve property of your route definitions

$stateProvider.state('stateName',{
    ...
    ...
    resolve: {
         isAuthorized: function(Auth){
             return Auth.checkAuthorization();
         }
    }
})

To support subsequent checks you could maintain a promise within the service This might look like:

myApp.service('Auth',function($http,$q){
    var authStatusDeferred = $q.defer();
    this.checkAuthorization = function(){
        return authStatusDeferred.promise;
    };

    this.validateToken = function(user){
        var isValid = false;
        //..do validation stuff
        if(isValid) authStatusDeferred.resolve();
        //Otherwise state change will not happen..            
    };



});

oh, sorry about no coffee

Geono

I guess it's too late for answering this question, but I want to comment here for someone who may need a little idea.

I've tried to do almost same thing for a long time and I stopped doing that. I don't think stateChangeStart listener is reliable to use. I think the best way to do your what you want is decorating $state.go using $provide service. Here is an example:

/* config your angular app */
.config(function($provide) {
    $provide.decorator('$state', function($delegate) {

        var myState = $delegate;
        // Rename original 'go' method
        myState.originalGo = myState.go;

        myState.go = function(toState, toParams, options) {

        /*  
         *  Do what you want to do :)
         */

        this.originalGo(toState, toParams, options);
    };

    return $delegate;
  });

With this approach, you can do whatever you want before $stateChangeStart. I hope it helps.

Ilya Chernomordik

I have found a very good way to make this work properly and not rely on resolve at all in another answer here. Here is the code:

rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState) {

    if (dataService.isInitialized()) {
        proceedAsUsual(); // Do the required actions based on the data you received in the service
    } 
    else {

        event.preventDefault();

        dataService.intialize().success(function () {
                $state.go(toState, toParams);
        });
    }
});

Then you can just remember that your data is already initialized in the service the way you like, e.g.:

function dataService() {

    var initialized = false;

    return {
        initialize: initialize,
        isInitialized: isInitialized
    }

    function intialize() {

        return $http.get(...)
                    .success(function(response) {
                            initialized=true;
                    });

    }

    function isInitialized() {
        return initialized;
    }
};
Pavel Blagodov

You should call $urlRouter.sync() after you have got user data. Also you might want to protect $stateChangeStart by using event.preventDefault() in case when user was not obtained.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!