3

In the code below, I'd like handling errors :

  • 401 : redirect to a login page
  • other : display error message (received in the message of the error)

I don't find the right way to do this.

Any idea ?

Thanks,

Module.js

var app;  
(function () {  
    app = angular.module("studentModule", []);  
})() 

Service.js

app.service('StudentService', function ($http) {    
    this.getAllStudent = function () {  
        return $http.get("http://myserver/api/Student/");  
    }  
});

Controller.js

app.controller('studentController', function ($scope, StudentService) { 

    function GetAllRecords() {  
        var promiseGet = StudentService.getAllStudent();  
        promiseGet.then(function (pl) { $scope.Students = pl.data },  
              function (errorPl) {  
                  $log.error('Some Error in Getting Records.', errorPl);  
              });  
    } 

});
2
  • 1
    You could use an http interceptor and do it in the common place Commented May 27, 2015 at 13:16
  • Yep, interceptors are the way to go. Commented May 27, 2015 at 14:30

1 Answer 1

4

As with most problems, there are many different ways to handle errors from AJAX requests in AngularJS. The easiest is to use an HTTP interceptor as already pointed out. This can handle both authentication and errors.

app.config(['$httpProvider', function($httpProvider) {
  $httpProvider.interceptors.push(['$rootScope', '$q', function($rootScope, $q) {

    return {
      responseError: function(rejection) {
        var deferred;

        // If rejection is due to user not being authenticated
        if ( rejection.status === 401 ) {

          $rootScope.$broadcast('unauthenticated', rejection);

          // Return a new promise since this error can be recovered
          // from, like redirecting to login page. The rejection and
          // and promise could potentially be stored to be re-run
          // after user is authenticated.
          deferred = $q.defer();
          return deferred.promise;
        }

        $rootScope.$broadcast('serverError', rejection);
        // Just reject since this probably isn't recoverable from
        return $q.reject(rejection);

      }
    }
  };
}]);

The above interceptor is created using an anonymous function but factories can be used to handle one or many different interceptors. The AngularJS docs have decent information about how to write different ones: https://docs.angularjs.org/api/ng/service/$http#interceptors

With the interceptors in place, you now just need to listen from the broadcasted events in your run method or any controller.

app.run(['$rootScope', '$location', function($rootScope, $location) {

  $rootScope.$on('unauthenticated', function(response) {
    // Redirect to login page
    $location.path('/login');
  });

  $rootScope.$on('serverError', function(response) {
    // Show alert or something to give feedback to user that
    // server error was encountered and they need to retry
    // or just display this somewhere on the page
    $rootScope.serverError = response.data.errorMessage;
  });
}]);

In your view:

<body ng-app="studentModule">
  <div id="server_error" ng-if="!!serverError">{{serverError}}</div>
  ...rest of your page
</body>

Like almost all AngularJS code, most of this can be abstracted into different factories and services but this should be a good place to start.

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

5 Comments

@Kris-I All the JavaScript can be pasted into your project after your studentModule is defined. I added a little bit more to my answer, including some example HTML, to get you started but actually handling the authentication and displaying errors is probably out of the scope of this question.
Well all this is strange for me :) I have : <html ng-app="app">
That's perfectly fine (and probably preferred), you don't need to change that. As long as you have your error DIV inside the tag where the ng-app is initialized. I would start by just setting $rootScope.serverError = "Oh, no, something went wrong!"; in the run block but outside the $on event handler just to make sure it shows up on your page.
I need on interceptor by service ? by controller ?
No, the reason why we set these in a config function is so they handle all requests for your entire application. Any service or controller that makes an HTTP call using $http will have any failing response run through our interceptor. No extra work necessary. Maybe spend some time learning about config and run in AngularJS. Steep learning curve but you'll definitely be productive once it clicks. Good luck!

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.