3

I have spent the entire day on this (hobby-programmer, not a real one). I admit up front that the issue is my lack of understanding of the basic fundamentals of angular (and most programming for that matter). I am especially new to web development and need some help.

Anyways, I have a template that I'm using for learning purposes, that's all this is really. It's the 'ani-theme' from startangular.com. I built some basic logic to authenticate a user (type 'aaa' in the email lol, remember, its just for learning). This code works fine, and if 'aaa' is entered then the router will be triggered to move you to the dashboard.

The problem is that the user could just put the URL for the dashboard in the browser and go there.

I have a variable called "authed" that is set to true once they log in, but I cant seem to 'conditionally route' the user to the dashboard when they type the URL in manually. I have tried so many things but no luck.

After 5 hours of research, i think it is due to the asynchronous nature of angular OR scope issues. Or both. Probably neither. idk.

I saw so many other posts about $stateChangeStart but it went way over my head. Can someone point me in the right direction here or try to explain what is going on here in dummy terms. I mean it, I really don't know much so dumb it down, I wont be insulted.

APP.JS

var authed = false;
var done = false;
var yapp = angular
  .module('yapp', [
    'ui.router',
    'ngAnimate',
    'myAuth'
  ])
  .config(function($stateProvider, $urlRouterProvider) {


      $urlRouterProvider.when('/dashboard', '/dashboard/overview');
      $urlRouterProvider.otherwise('/login');

    $stateProvider
      .state('base', {
        abstract: true,
        url: '',
        templateUrl: 'views/base.html'
      })
      .state('login', {
        url: '/login',
        parent: 'base',
        templateUrl: 'views/login.html',
        controller: 'LoginCtrl'
      })
      .state('dashboard', {
        url: '/dashboard',
        parent: 'base',
        templateUrl: 'views/dashboard.html',
        controller: 'DashboardCtrl'
      })
      .state('overview', {
        url: '/overview',
        parent: 'dashboard',
        templateUrl: 'views/dashboard/overview.html'
      })
      .state('reports', {
        url: '/reports',
        parent: 'dashboard',
        templateUrl: 'views/dashboard/reports.html'
      });

  });

LOGIN.JS

angular.module('yapp')
  .controller('LoginCtrl', function($scope, $location, authFactory) {
      $scope.submit = function(emailp) {
        if(authFactory.checkAuth(emailp)) {
          $location.path('/dashboard');
        }else{
          alert("WRONG");
        }
      }
    });

AUTH.JS

var myAuth = angular.module('myAuth', [])
  .factory('authFactory', function(){
    var factory = {};
    factory.checkAuth = function(emailp){
      if(emailp == 'aaa') authed = true;
      return(authed);
    };
    return factory;
  });

IMPORTANT SIDE NOTE

I love advice and help, so please, if you see other things I'm doing that just look ridiculous, please call me out. It will help me a lot.

------------------------------------------------

EDIT EDIT EDIT EDIT EDIT

Thanks for the answers so far! I am going to try implementing @swestner 's answer and once it is working, I will study the 'why' part so I can really understand.

I do have another question on this same issue to clarify so that I can better understand why my other method wasn't working. I am very curious because it is a strange behavior.

So, You see my authed variable is declared in app.js, and then in the auth.js factory it is set to true or false depending on the users 'emailp'. I added some logic to the app.js saying 'if authed is true, use these route commands, otherwise use these ones.

example:

console.log(authed) //this actually does print the correct value...
if(authed) {  //however this doesnt work!
  $urlRouterProvider.when('/dashboard', '/dashboard/overview');
  $urlRouterProvider.otherwise('/login');
}else{
  $urlRouterProvider.when('/dashboard', '/login');
  $urlRouterProvider.otherwise('/login');
}

I can print the correct value, however the condition is always true.

HOWEVER, if I declare the variable authed2 RIGHT before the conditional statement it works fine!

var authed2 = true;

console.log(authed + " #1");
console.log(authed2 + ' #2');

if(authed2) {
  $urlRouterProvider.when('/dashboard', '/dashboard/overview');
  $urlRouterProvider.otherwise('/login');
}else{
  $urlRouterProvider.when('/dashboard', '/login');
  $urlRouterProvider.otherwise('/login');
}

The program knows both values to be true, I can even print them both right before the conditional, however when I use authed (set and declared elsewhere) the conditional doesnt work (even tho it seems to know the answer).

Its confusing me and I have to be missing some background behavior here.

5
  • May be check if user authorized in your controller and redirect to login if user not authorized. Commented Sep 11, 2015 at 5:27
  • Checking in the controller will cause a lot of boilerplate and spreads the logic across the application. Its much better to encapsulate the logic and keep the code DRY. Commented Sep 11, 2015 at 5:49
  • 1
    I added a rather large edit. It's almost an entire new question in size but it is directly linked to my problem and it will really help me understand why my own method wasn't working. Commented Sep 11, 2015 at 15:22
  • 1
    This really should be a separate question. The issue is that the angular.config is only run once during initialisation. That means by the time you are logging in, the condition has already been evaluated and does not run again. Commented Sep 12, 2015 at 17:05
  • 1
    Wow that is pretty interesting, I will have to look into that! Thanks for pointing me in the right direction there. I'll do my research on this and if I still cant figure it out, of course, I will post it separately. Commented Sep 13, 2015 at 17:22

1 Answer 1

4

The $stateChangeStart event is the proper place to handle this. This event will fire when you try to navigate to a url. At that point you can check if the user is authenticated, and if not, bounce them back to login.

You would hook up the event like this :

angular
  .module('yapp')
  .run(function ($rootScope, $state, authFactory) {
    $rootScope.$on('$stateChangeStart', function () {
      if(!authFactory.isAuthed()){
        $state.go('login')
      }
    })
  });

And update your auth factory to have the isAuthed method.

var myAuth = angular.module('myAuth', [])
  .factory('authFactory', function () {
    var factory = {};
    factory.checkAuth = function (emailp) {
      if (emailp == 'aaa') authed = true;
      return (authed);
    };

    factory.isAuthed = function () {
      return authed;
    }
    return factory;
  });
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks @swestner! This is the kind of answer I was expecting, but since you used my actual code it makes much more sense to me, thank you so much!!!
I'm glad to help! Please mark the answer as correct if it is.
I was just barely able to try it today and am getting an error. "RangeError: Maximum call stack size exceeded". The error occurs as soon as the "$state.go('login')" line is reached. Also, the page takes much longer to load. Eventually it gets to the page, but no behavior has changed, I can still get to the dashboard without logging in :-/
Its difficult to say what the problem is without knowing the current state of your code. Are you using the changes made stated in the question edit? Have you changed anything else? This line in particular could be problematic, since it will bounce back to login every time you hit the dashboard url $urlRouterProvider.when('/dashboard', '/login');
what is authed in this case
|

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.