1

I'm starting to learn AngularJS and so far so good but I am currently stuck on a small issue about an synchronous function.

I would like the function AuthenticationSharedService.login() to be called and returned before executing the rest of the code. How can I do that?

app.js

myApp.config(['$routeProvider', '$httpProvider', 'USER_ROLES',
    function ($routeProvider, $httpProvider, USER_ROLES) {
        $routeProvider
            .when('/login', {
                templateUrl: 'views/login.html',
                controller: 'LoginController',
                access: {
                    authorizedRoles: [USER_ROLES.all]
                }
            })
            .when('/error', {
                templateUrl: 'views/error.html',
                access: {
                    authorizedRoles: [USER_ROLES.all]
                }
            })
            .otherwise({
                templateUrl: 'views/main.html',
                controller: 'MainController',
                access: {
                    authorizedRoles: [USER_ROLES.user]
                }
            });
    }])
    .run(['$rootScope', '$location', 'AuthenticationSharedService', 'Session', 'USER_ROLES',
        function($rootScope, $location, AuthenticationSharedService, Session, USER_ROLES) {
            $rootScope.$on('$routeChangeStart', function (event, next) {

                <!-- Bit of code to execute before going further -->
                if (!Session.login) {
                    console.log('First attempt to login');
                    AuthenticationSharedService.login();
                }
                <!-- /////////////////////////////////////////// -->

                if (AuthenticationSharedService.isAuthenticated()) {
                    // user is not allowed
                    $rootScope.$broadcast("event:auth-notAuthorized");
                } else {
                    // user is not logged in
                    $rootScope.$broadcast("event:auth-loginRequired");
                }
            });
        }]);

authenticationSharedService.js

myApp.factory('AuthenticationSharedService', ['$rootScope', '$http', '$cookieStore', 'authService', 'Session', 'Account',
    function ($rootScope, $http, $cookieStore, authService, Session, Account) {
        return {
            login: function () {
                return Account.get(function(data) {
                    Session.create(data.login, data.roles);
                    authService.loginConfirmed(data);
                });
            }
        };
    }]);
TheEwook
  • 11,037
  • 6
  • 36
  • 55
  • Resolve? http://stackoverflow.com/questions/11972026/delaying-angularjs-route-change-until-model-loaded-to-prevent-flicker – Jazzy Apr 10 '14 at 22:31

1 Answers1

3

You need to use resolve. See http://docs.angularjs.org/api/ngRoute/provider/$routeProvider or http://www.bfcamara.com/post/66001429506/authentication-in-a-spa-with-angular - this second link is quite good.

Resolve is a map of dependencies that should be injected into the controller. If any of the mapped objects are functions, the functions will be evaluated and their return values injected. If a function returns a promises, the view will not be rendered until the promise is resolved.

Just FYI, the view will not be rendered at all if the promise is rejected. You would want to deal with that situation in $rootScope.$on('routeChangeError', functionToHandleRejection)

Here's an example that should work for you:

.when('someUrl', {
  resolve: {
    object: function(AuthenticationSharedService) {
      return AuthenticationSharedService.login();
    }
  }
})
Robert Balicki
  • 1,583
  • 2
  • 16
  • 24
  • This! this is what I was looking for "If a function returns a promises, the view will not be rendered until the promise is resolved." – TheEwook Apr 11 '14 at 08:58