AngularJS : angular-ui-router always redirects to $urlRouterProvider.otherwise location

15,671

Solution 1

I found I didn't have a '/' at the beginning of my initial state url. Every time I navigated to the state, the missing '/' seemed to push it into the stateProvider.otherwise.

state1: 'opportunity'
state1Url : '/opportunity/' <== added initial forward slash to make it work.

state2: 'opportunity.create'
state2Url : 'create/'

Solution 2

The first path to be recognised will be the selected as the current location. This means that the order of your route definitions is crucially important. In your case you only have a single catch-all otherwise route definition and since all routes match this then all routes are directed to your login page ignoring any other route definitions you may have, including all your stateProvider state definitions.

One way to fix this is to remove the urlRouterProvider route definition altogether and instead use the *path syntax provided by ui-router to create an alternative otherwise state (which must be defined last for the same reasons given above).

Therefore your code might look something like this:

$stateProvider
    .state('auth', {
        url: '/auth',
        templateUrl: 'views/authView.html',
        controller: 'AuthController as auth'
    })
    .state('users', {
        url: '/users',
        templateUrl: 'views/userView.html',
        controller: 'UserController as user'
    })
    .state('subjects', {
        url: '/users/:user_id/subjects',
        templateUrl: 'views/subjectsView.html',
        controller: 'SubjectsCtrl as subjectsCtrl'
    })
    .state('subject', {
        url: '/users/:user_id/subjects/:subject_id',
        templateUrl: 'views/subjectView.html',
        controller: 'SubjectCtrl as subjectCtrl'
    })
    .state("otherwise", {
        url: "*path",
        templateUrl: 'views/authView.html',
        controller: 'AuthController as auth'
    });
Share:
15,671
Brent Parker
Author by

Brent Parker

Updated on July 01, 2022

Comments

  • Brent Parker
    Brent Parker almost 2 years

    I'm trying to create an SPA where you have to be logged in to access almost everything. So naturally, the default screen you see is the login screen. However, after a user has logged in, no matter what the ui-sref is, ui-router redirects to the login page (even when the user is authenticated). Here is my ui-router code:

    (function () {
    'use strict';
    angular
        .module('app', ['ui.router', 'satellizer'])
        .config(function ($stateProvider, $urlRouterProvider, $authProvider, $httpProvider, $provide) {
      
            $httpProvider.interceptors.push(['$q', '$injector', function($q, $injector){
                return {
                    responseError: function (rejection) {
                        var $state = $injector.get('$state');
                        var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
                        angular.forEach(rejectionReasons, function (value, key) {
                            if (rejection.data.error === value) {
                                localStorage.removeItem('user');
                                $state.go('auth');
                            }
                        });
    
                        return $q.reject(rejection);
                    },
                    response: function(response) {
                        var authorization = response.headers('authorization');
                        if(authorization !== null) {
                            authorization = authorization.substr(7).trim();
                            //console.log(authorization);
                            var $auth = $injector.get('$auth');
                            $auth.setToken(authorization);
                        }
                        return response;
                    }
                }
            }]);
    
            $authProvider.loginUrl = 'mingdaograder/api/authenticate';
    
            $stateProvider
                .state('users', {
                    url: '/users',
                    templateUrl: 'views/userView.html',
                    controller: 'UserController as user'
                })
                .state('subjects', {
                    url: '/users/:user_id/subjects',
                    templateUrl: 'views/subjectsView.html',
                    controller: 'SubjectsCtrl as subjectsCtrl'
                })
                .state('subject', {
                    url: '/users/:user_id/subjects/:subject_id',
                    templateUrl: 'views/subjectView.html',
                    controller: 'SubjectCtrl as subjectCtrl'
                })
                .state('auth', {
                    url: '/auth',
                    templateUrl: 'views/authView.html',
                    controller: 'AuthController as auth'
                });
                //.state('otherwise', {
                //    url: '*path',
                //    templateUrl: 'views/authView.html',
                //    controller: 'AuthController as auth'
                //});
    
                //$urlRouterProvider.otherwise('/auth');
                $urlRouterProvider.otherwise(function($injector, $location) {
                    console.log("Could not find " + $location);
                    $location.path('/auth');
                });
        })
        .run(function ($rootScope, $state, $log) {
            $rootScope.$on('$stateChangeStart', function (event, toState) {
                    console.log(toState.name);
                var user = JSON.parse(localStorage.getItem('user'));
                if (user) {
                    $rootScope.authenticated = true;
                    $rootScope.currentUser = user;
                }
            }
            );
        }
    );
    })();

    Anytime I try to use $state.go(any state name here) or even type the address into the address bar, I am always redirected to the auth state. On the console the message is "Could not find http://localhost/#/" for every single route. I can type in http://localhost/#/users/5/subjects and I get the same message.

    Here is one of my controllers doing a redirect:

    (function () {
        'use strict';
    
        angular
            .module('app')
            .controller('AuthController', AuthController);
    
        function AuthController($auth, $state, $http, $rootScope, $log) {
            var vm = this;
    
            vm.loginError = false;
            vm.loginErrorText;
    
            vm.login = function () {
                var credentials = {
                    username: vm.username,
                    password: vm.password
                };
    
                $auth.login(credentials).then(function () {
                    return $http.get('api/authenticate/user');
                }, function (error) {
                    vm.loginError = true;
                    vm.loginErrorText = error.data.error;
                }).then(function (response) {
                    var user = JSON.stringify(response.data.user);
                    localStorage.setItem('user', user);
                    $rootScope.authenticated = true;
                    $rootScope.currentUser = response.data.user;
    
                    //$log.info('From AuthCtrl: ' + $rootScope.currentUser.id);
                    $state.go('subjects', {user_id:$rootScope.currentUser.id});
                });
            }
        }
    })();

    Any ideas what I'm doing wrong? Thanks a lot for your time.

    Update: Ok, I haven't found a way to fix it but I think I may have found a possible cause. It seems to only happen for the routes with parameters. For example, if I go to the users state, whose path is /users, there is no redirect. However, if I go to the subjects state, whose path is /users/:user_id/subjects, it does redirect. It's like the Url matching service can't recognize that /users/5/subjects matches /users/:user_id/subjects, so redirects. Any ideas how to work around this?

  • Sunil D.
    Sunil D. over 8 years
    This cannot be true. In one of my apps I declare the "otherwise" route first, and it works just fine. A couple of reasons for this: 1) Note that you're using two different objects ($stateProvider and $urlProvider), you're not adding to or removing from the state hierarchy when you register the "otherwise" route. 2) UI Router states can be registered in any order. This is so you can put state definitions in Angular modules.
  • Brent Parker
    Brent Parker over 8 years
    Sorry, I tried this and it didn't change anything. It's still redirecting exactly as it was before. Any other ideas?
  • Brent Parker
    Brent Parker over 8 years
    @biofractal - Tried adding the *path code, too. It is still redirecting everything but now instead of having /#/auth in the address bar it just has /#/
  • Suever
    Suever about 8 years
    Please provide some description of your code and how it addresses the poster's question rather than simply posting a giant block of code