0

I am working on an angular app. It's an SPA. I am loading the profile(or myAccount) page into the home page when user clicks on a link.

<a href="#" ng-click="getProfileData()"/></a>

in my controller:

$scope.getProfileData(){
    $http.get('/profile').then(
        function success(){
        },
        function error(){
        }
    }
}

the link makes an ajax request through $http service of angular.

what I want to do is, when user clicks on the link, before making the ajax request to check if he's logged in or not. if not, open the sign in popup, and after sign in continue with the same request.

I've looked into $httpProvider.interceptors, but I'm still not sure how to do it, since I need to pause hold the $http request till the login is completed, modify the config by adding login details into it and then continue.

Is using of interceptors the correct option? If yes, how should I proceed towards my objective?

EDIT:

my primary concern is to continue with the same request. i.e. i don't want the user to click on profile link again after he has logged in. i can check if user is logged in or not before making the ajax request. if he is, then it's good. but if he's not, he has to log in (in the modal i pop up), and then he has to click on the profile link again. is there a way to continue the previous http request after login?

Mridul Kashyap
  • 684
  • 5
  • 12
  • Yes interceptors are the correct way to check data between requests – Shannon Hochkins May 26 '16 at 08:13
  • Possible duplicate of [AngularJS- Login and Authentication in each route and controller](http://stackoverflow.com/questions/20969835/angularjs-login-and-authentication-in-each-route-and-controller) – Shannon Hochkins May 26 '16 at 08:59
  • i wouldn't think this question is a possible duplicate of that, since my question is about `$http` request. the difference is, in case of `$location.path` the location(value, oldValue in the question you mentioned) changes, and we can perform our functionality after `$routeChangeStart` and before `$routeChangeSuccess`. the significant difference here is there's no route is not changing here, it's just a request. Please tell me if i am wrong about "route not changing". I am quite new to it. – Mridul Kashyap May 26 '16 at 09:18
  • You've mentioned `ui-router`, you've mentioned that you need to cover the login status within a http request, which the post I've tagged a duplicate covers completely. I would refer to that post completely for your answer – Shannon Hochkins May 26 '16 at 10:01

2 Answers2

2

There are only three points in the application where the login modal should appear:

  1. When you are on a welcome page and you click “Login”.
  2. When you are not logged in and you attempt to visit a page that requires login.
  3. When you attempt to make a request that requires a login(Ex:session expiration).

Determining which pages require a logged in user

Considering you are using ui router,you can secure routes of your application with the help of attaching additional properties to a route.Here we add a requireLogin property for each state.

app.config(function ($stateProvider) {

  $stateProvider
    .state('welcome', {
      url: '/welcome',
      // ...
      data: {
        requireLogin: false
      }
    })
    .state('app', {
      abstract: true,
      // ...
      data: {
        requireLogin: true // this property will apply to all children of 'app'
      }
    })

});

For routes that do not require a login we set requireLogin to false.


Capturing attempted state changes

This is where we are going to capture the attempted state changes and inspect them for our requireLogin property.

app.run(function ($rootScope) {

  $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
    var requireLogin = toState.data.requireLogin;

    if (requireLogin && typeof $rootScope.currentUser === 'undefined') {
      event.preventDefault();
      $rootScope.returnToState = toState.url;
      // get me a login modal!
    }
  });

});

As you can see, if the route requires a login and $rootScope.currentUser is not yet set, we will prevent the attempted state change and show the modal.


Redirecting to initially requested url after login

The last part requires redirecting to the initially requested url after login.In our app.run we have set a variable $rootScope.returnToState = toState.url which we can use in our login controller to redirect.In our controller for the login page we can do something like this:

$scope.login = function(form) {
  $scope.submitted = true;

  if(form.$valid) {
    Auth.login({
      email: $scope.user.email,
      password: $scope.user.password
    })
    .then( function() {
      // Logged in, redirect to correct room
      if( $rootScope.returnToState) {
        $location.path($rootScope.returnToState);
      } else {
        //redirect all others after login to /rooms
        $location.path('/home');
      }
    })
    .catch( function(err) {
      $scope.errors.other = err.message;
    });
  }
};

For further reference please refer to this blog post http://brewhouse.io/blog/2014/12/09/authentication-made-simple-in-single-page-angularjs-applications.html

This can help you build a rock solid authorization for your app which I think you might be looking for.

Denny John
  • 464
  • 7
  • 19
  • is it possible to do it without ui-router? i would have preferred to use core library only, that's why i mentioned `$http.interceptor`. this solution, although doesn't show that it will work for ajax requests too, still looks good and worth a try. but i would prefer to use the core functionality of angular if possible. thanks for your help though, if i can't figure it out, i'll try this. – Mridul Kashyap May 26 '16 at 09:45
  • ui router supports everything the normal ngRoute can do as well as many extra functions.ui-router allows for nested views and multiple named views. This is very useful with larger app where you may have pages that inherit from other sections.I hope your application will be having such kind of needs.So it would be better to use ui router. – Denny John May 26 '16 at 09:59
1

Why can't you just make another function call to verify, if the user is logged-in. And based on that fire up the ajax request that you are trying up there. Something like

$scope.getProfileData(){
    if($scope.isLoggedin()){
        $http.get('/profile').then(
            function success(){
            },
            function error(){
            }
        }
    }
};

$scope.isLoggedin = function(){
    // Do some processing and return true/false based on if user is logged-in
};
seekers01
  • 545
  • 1
  • 4
  • 11
  • the problem is not just checking if user is logged in or not. the real problem is how to continue the same request after the login is done(in case when user is not already logged in, the login modal pops up, and he enters his credentials). i know, i can put openLogin like this: `if($scope.isLoogedin()){ //run ajax } else{ openLogin(); }` but after he logs in, he'll have to click the same link again. – Mridul Kashyap May 26 '16 at 08:11