9

Can you tell me what is the correct way to redirect to another page if $http.post returns a specific error code.

Just to add context, I want to redirect to another page if the user is not logged in or authorized to use the API.

  function getData(filter) {
     var deferred = $q.defer();
     var data = JSON.stringify(filter);

      $http.post('/myapp/api/getData', data)
         .success(function (data, status, headers, config) {
            deferred.resolve(data);
         })
              .error(function (error) {
                 deferred.reject(error);
              });

     return deferred.promise;
  }
3
  • 1
    a page or a route? If it's a page, just a vanilla javascript redirect will work. Commented Oct 21, 2016 at 22:16
  • @Ronnie to a page. Commented Oct 21, 2016 at 22:20
  • I think the question is kind of duplicate of stackoverflow.com/questions/11541695/…. You should use $location service docs.angularjs.org/api/ng/service/$location. That is $location.path('/login'); for example. Commented Oct 23, 2016 at 21:54

7 Answers 7

3

You could do a redirect to the page using $window.location.href, based on the error condition you have.

var app = angular.module("sampleApp", []);

app.controller("sampleController", [
  "$scope",
  '$window',
  'sampleService',
  function($scope, $window, sampleService) {
    sampleService.getData().then(function(result) {}, function(error) {
      if (error.statusCode === 400) {
        alert("Error");
        $window.location.href = "http://stackoverflow.com"
      }
    });
  }
]);
app.service("sampleService", function() {
  this.getData = function() {
    var promise = new Promise(function(resolve, reject) {
      setTimeout(function() {
        reject({
          statusCode: 400
        });
      }, 1000);
    });
    return promise;
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-App="sampleApp">
  <div ng-controller="sampleController">
  </div>
</div>

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

4 Comments

Can I just have an else with deferred.reject(error); after the $window.location.href?
i dont understand what you mean ? can you elaborate please?
So for a specific error I want to "redirect". But for all others I want to deferred.reject(error); Will that work?
thats exactly what I have in the errorCode check to 400 in the controller .then method. Usually, Services are not meant to diverge on the response it receives. Services responsibility is to make a call and return. It is up to the controller to read and decide what to do with the data it received. By doing so, your services are independent and can be reused. if not a particular service will only work coupled with a controller which isn't advised.
3
+50

The best way to catch global AuthenticationErrorin angular is with interceptor. This way you can monitor all request that are sent from angular and check for AuthenticationError.

$provide.factory('AuthErrorInterceptor', function($q, $location) {
  return {
   'responseError': function(rejection) {

        //check for auth error

        $location.path('/login');

        return $q.reject(rejection);
    }
  };
});

Comments

3

Example :

  $http.post('/myapp/api/getData', data)
     .then(function (data) {
         if(data.ErrorCode==1)
        {
             $window.location.href="controllerName/actionName";
        }
     })

Comments

3

Use a interceptor service in order to centralize all of your rejection request in the same service.

module.config(['$httpProvider', ($httpProvider: ng.IHttpProvider) => {
    $httpProvider.interceptors.push('errorService');
}]);


module.factory('errorService', ['$location', function($location) {  
   var errorService = {
       responseError: function(rejection) {
           if (rejection === '401') {
               $location.path('/login');
           }
       }
    };
    return errorService;
}]);

Comments

2

The $http.post is misguiding. So far the best answer is @Kliment's. Interceptors are the best way to manage what comes before and after http requests.

However, if your end goal is to prevent access to a page, you have to at least use a routing plugin (ngRoute, ui-router) because with the promise idea there will always be a delay between the http request and the response.

Depending on server response time you'll still see the page display for about a second or so.

With ui-router you simply configure a resolve method for each state you want to protect. It could look like this:

.state('protected',
{
    url : '/protected_page',
    templateUrl : 'secret.html',
    resolve: {
        loggedin: loggedin
    }
})

loggedin refers to a function you define that contains your $http.post call (or better yet a service)

function loggedin($timeout, $q, $location, loginService) {
    loginService.then(function(data) {
        if(data.status == 401) {
            //$timeout(function() { $location.path('/login'); });
            return $q.reject();
        } else {
            return $q.when();
        }
    });
}

Here this particular service returns a 401 status but you can return anything.

The state will not be resolved (and the page not displayed) until it's accepted or rejected.

You can redirect directly from there if you want, although it's not very elegant. ui-router gives you another option with default redirection:

if (tokenIsValid()) 
    $urlRouterProvider.otherwise("/home");
else
    $urlRouterProvider.otherwise("/login");

With otherwise you tell ui-router to go to certain urls if no state exists for a particular request or if a resolve has been rejected.

On another subject, your http request is badly written.

.success and .error are deprecated and you don't need to create a promise ($q) over an $http request that itself already returns a promise.

You have a good example in the documentation linked above.

Comments

2

You can redirect to page on unauthorized access of a user based on the status code which you can return from your API call.

$http({
method: "POST",
url: 'Api/login',
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
}).success(function (data,status) {
if(status==200){
    alert('Successfully logged in');
    $location.path('/dashboard'); //You can use this if you are defined your states.
}
}).error(function (data,status) {
    if(status==403||status==403){ //Based on what error code you are returning from API
     $location.path('/login');// if states are defined else
     $window.location.href = "https://www.google.com";
    }
});

Comments

2

First of all Nice Question , In this scenario You Can use $location , $state If it is external url You can use $window.location.href ... I would recommend $location and it is the best way ...

Please See the link for further Using $window or $location to Redirect in AngularJS

    function getData(filter) {
         var deferred = $q.defer();
         var data = JSON.stringify(filter);



    $http.post('/myapp/api/getData', data)
             .success(function (data, status, headers, config) {
                deferred.resolve(data);

if(data.errorcode==9999)  // Define Your  Error Code in Server
{

    $location.path('/login'); // You Can Set Your Own Router 

}             })
                  .error(function (error) {

    $location.path('/login'); // You Can Set Your Own Router 
                     deferred.reject(error);
                  });

         return deferred.promise;
      }

Preferably use $location or $state ...

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.