1

How can I delay/defer a route/controller until an anonymous function returns? On app bootstrap, I default rootScope.me as guest account until it can check cookies for a logged in user.

I have a controller, testCtrl, that relies on rootScope.me data to load appropriate user data. The controller is fired before rootScope.me has a chance to be set to the user.

I know Angular has $q service for resolving promises, but am not sure how to apply this to routing.

angular
    .module('DDE', [])
    .run(['$rootScope', 'Me', function($rootScope, Me) {

        $rootScope.me = {
            username : 'Guest',
            id : -1
        };

        if (Cookies.get('user_id') && Cookies.get('username')) {
            Me.getProfile({user_id : Cookies.get('user_id')}).success(function (res) {
                $rootScope.me = res;
            }).error(function (err) {
                console.log('Error: ', err);
            });

        }
}])
.config(['$routeProvider', '$httpProvider', '$authProvider',
           $routeProvider.
                when('/test', {
                    templateUrl: '/html/pages/test.html',
                    controller: 'testCtrl'
                }).

.config(['$routeProvider', '$httpProvider', '$authProvider', '$stateProvider', '$urlRouterProvider',
    function($routeProvider, $httpProvider, $authProvider, $stateProvider, $urlRouterProvider) {

       //Cannot inject services like Me or $rootScope as I need

        function loadProfile () {
            Me.getProfile({user_id : Cookies.get('user_id')}).success(function (res) {
                $rootScope.me = res;
            }).error(function (err) {
                console.log('Error: ', err);
            });
        }

        $stateProvider.
            state('test', {
                url : '/test',
                templateUrl: '/html/pages/test.html',
                controller : 'testCtrl',
                resolve : {
                    ProfileLoaded : function () {
                        return loadProfile();
                    }
                }
            });
user3871
  • 12,432
  • 33
  • 128
  • 268

1 Answers1

2

edit: adding angular's ngRoute example.

You can look into ui-router's resolve. It basically waits for your promise to be resolved before loading/navigating to your state/route.

documentation

Each of the objects in resolve below must be resolved (via deferred.resolve() if they are a promise) before the controller is instantiated. Notice how each resolve object is injected as a parameter into the controller.

Here's angular's ngRoute example from angular's documentation:

.config(function($routeProvider, $locationProvider) {
  $routeProvider
   .when('/Book/:bookId', {
    templateUrl: 'book.html',
    controller: 'BookController',
    resolve: {
      // I will cause a 1 second delay
      delay: function($q, $timeout) {
        var delay = $q.defer();
        $timeout(delay.resolve, 1000);
        return delay.promise;
      }
    }
  })
Community
  • 1
  • 1
Henry Zou
  • 1,809
  • 1
  • 14
  • 19
  • So `$routeProvider` has no support for defer'ds? So I have to swap out my `routeProvider` with `stateProvider`? – user3871 Jan 01 '16 at 19:18
  • $routeProvider also support Resolve. Another solution I am using right now is to block the page with BlockUI – Tony Bao Jan 01 '16 at 19:21
  • I've added ngRouter example – Henry Zou Jan 01 '16 at 19:33
  • @HenryZou Hi. Plz see above. How can I inject services, like `Me` or `$rootScope` as needed when I am resolving? In the `config` stage, you cannot ask for instances other than providers (http://stackoverflow.com/questions/10486769/cannot-get-to-rootscope) – user3871 Jan 01 '16 at 20:37
  • delay: function($q, $timeout) { var delay = $q.defer();4 $timeout(delay.resolve, 1000); return delay.promise; } – Henry Zou Jan 01 '16 at 20:41
  • @HenryZou but I am using `$stateProvider` now. See above – user3871 Jan 01 '16 at 20:42
  • Simply specify it in the function param.. ProfileLoaded : function (me) { return me.loadProfile(); } – Henry Zou Jan 01 '16 at 20:44