Search code examples
angularjsstateresolve

resolve promise until state changes


There is a hidden page in my angular app, so only special id user can access it. To implement it I send HTTP get request to the server (because only the server knows that special id) when state changes to that hidden state.

And if server responses to me with an error message then I prevent state changing process, in other case user goes to that special page.

Here is the code I am using:

angular
.run(["$rootScope", "$location", "$state", "mySvc", function ($rootScope, $location, $state, mySvc) {
    var id = mySvc.getId();    
    $rootScope.$on( '$stateChangeStart', function(event, toState  , toParams, fromState, fromParams) {

        if(toState.name === "specialstate") {
            mySvc.check(id)
                .then(function(result) {
                    if(result.error !== 0) {
                        event.preventDefault();
                    }
                }, function(error) {
                    event.preventDefault();
                });                
        }

    });
}]);

Function in service:

        function check(id) {
        var deferred = $q.defer();
        $http({
            url: "/api/url",
            method: "GET",
            headers: {'Content-Type': 'application/json'}
            }).
            then(function (result) {
                console.log(result);
                if(result.data.error === 0) {
                    deferred.resolve(result.data);
                }
                else {
                    deferred.reject(result.data);
                }
            }, function (error) {
                deferred.reject(error);
            });
        return deferred.promise;
    };

Everything is right, except one thing: the state is being changed without waiting for request result. I think I should use resolve, but I do not know how to use it properly.

Thanks.


Solution

  • ui-router supports a resolve object that defines aset of data that should be resolved (from server, for instance), before the state transition is allowed.

    .state('hidden', {
      url: '/hidden',
      ...
      resolve: {
        data: function(mySvc) {
          var id = mySvc.getId();    
          return mySvc.check(id).then(function(result) {
            if (result.error !== 0) {
              throw new Error("not allowed");
            }
          });
        }
      }
    });
    

    The data object defined would be available to your controller in that hidden state, and only in case it returns a 2xx status code and there's an error property equal to 0.

    If data is resolved, then a state change occurs and a controller is instantiated. In case of rejection, none of this takes place.

    As a personal note, I find that a great device to handle authorization.