Angular ui-router: How to defer rendering the template until authorization is complete?

angular-ui-router, angularjs

Solution

What about using a resolve-block?

.state('app.dashboard', {
    url: '/dashboard', 
    views: {
        menuContent: {
            templateUrl: 'dashboard/dashboard.html',
            controller: 'DashboardCtrl',
            resolve: {
                login: function($q, Auth) {
                    var deferred = $q.defer();
                    Auth.getCurrentUser().then(function(currentUser) {
                        if (currentUser == null) {
                            deferred.reject();
                        } else {
                            deferred.resolve();
                        }
                    });
                    return deferred.promise;
                }
            }
        }
    }
})

The state-change won't happed untill the promise is resolved so the template should not be showing. Rejecting the promise will raise a `$stateChangeError` according to this answer so you would need to handle that error and redirect to the login-page.

Problem

My ui-router configuration is this: ``` $stateProvider .state('app', { url: '/app', abstract: true, templateUrl: 'sidemenu/sidemenu.html', controller: 'SideMenuCtrl' }) .state('login', { url: '/login', templateUrl: 'login/login.html', controller: 'LoginCtrl' }) .state('app.dashboard', { url: '/dashboard', views: { menuContent: { templateUrl: 'dashboard/dashboard.html', controller: 'DashboardCtrl' } } }) [More states here] $urlRouterProvider.otherwise('/app/dashboard'); ``` When user navigates to `/app/dashboard` I would like to check if they are authorized, and then: - redirect to `/login` if they are not authorized, or - allow to see the dashboard if they are authorized This seems to do the trick: (based on this example) ``` $rootScope.$on('$stateChangeSuccess', function(event) { var path = $location.path(); if (path === '/login') { return; } // Halt state change from even starting event.preventDefault(); Auth.getCurrentUser().then(function(currentUser) { if (currentUser === null) { $state.go('login'); } else { // Continue with the update and state transition $urlRouter.sync(); } }); }); ``` The only problem with this solution is that, if a non-authorized user navigates to the dashboard, the dashboard template is visible first. Only when the authorization response is coming back it changes to the login template. Is there a way not to show the dashboard while we authorize the user? I also tried to change `$stateChangeSuccess` to `$stateChangeStart`, but it didn't really work (routing seems to be completely broken then).

Original source

Related problems