Search code examples
javascriptangularjsangular-ui-routerrestangular

In Angular, Is there a way to do some initial logic before any controller or directive is instantiated but after the app is bootstrapped?


I'm developing an Angular single page app by using Restangular and ui-router. Now i met an issue, i need to call some initial server api to get some global data before any directive or controller is instantiated and after angular is bootstrapped (angular.bootstrap). My app is bootstrapped manually by call angular.bootstrap instead of using ng-app directive.


Updated: Thanks @alp and @radim-köhler.

I have tried both the 'resolve' and the 'run' method, but it seems that either of them can resolve my issue. I have tried them with following code. My requirement is both the 'hello-world' directive and the 'HomeCtrl' can be blocked or delayed to be instantiated until the resolve1 or resolve2 is resolved, but now the test result is:

  1. The resolve2 specified in $stateProvider.state's resolve object only can block the instantiation of HomeCtrl, hello-world directive is still be instantiated before the resolve2 is resolved.
  2. The resolve1 in the module's 'run' method can NOT block any of them (HomeCtrl controller or hello-world directive).

I also create this in Plunker

Maybe i need to wrap the hello-wrold directive and the HomeCtrl into another controller and declare an abstract or normal state for the controller, right?

angular.module('app', ['restangular', 'ui.router'])
  .directive('helloWorld', function() {
    console.log('Initialize hello-world directive.');
    return {
      restrict: 'E',
      scope: {
        name: '@'
      },
      template: '<span>Hello <strong>{{name}}</strong></span>'
    }
  })
  .controller('HomeCtrl', function($scope) {
    console.log('Initialize home page.');
    $scope.content = 'This is in HomeCtrl';
  })
  .config(function($stateProvider, $urlRouterProvider) {
    $stateProvider.state('home', {
      url: '/',
      controller: 'HomeCtrl',
      template: '<div class="body">{{content}}</div>',
      resolve: {
        init: function($q) {
          return $q(function(resolve, reject) {
            setTimeout(function() {
              console.log('Resolving2 ...'); // resolve2
              resolve();
            }, 1000 * 3);
          });
        }
      }
    });
    $urlRouterProvider.otherwise('/');
  })
  .run(function(Restangular, $q) {
    console.log('App module is starting...');
    //console.log(Restangular, $q);
    return $q(function(resolve, reject) {
      setTimeout(function() {
        console.log('Resolving1 ...'); // resolve1
        resolve();
      }, 1000 * 5);
    });
  });

angular.element(document).ready(function() {
  angular.bootstrap(document, ['app']);
});
.body {
  margin-top: 10px;
}
<!DOCTYPE html>
<html>

<head>
  <script src="//code.angularjs.org/1.3.10/angular.js"></script>
  <script src="//rawgit.com/angular-ui/ui-router/0.2.13/release/angular-ui-router.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/restangular/1.4.0/restangular.min.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body>
  <hello-world name="World"></hello-world>
  <div ui-view=""></div>
</body>

</html>

The output in console is:

App module is starting...
Initialize hello-world directive.
Resolving2 ...
Initialize home page.
Resolving1 ...


Solution

  • make a super state with ui-router

    $stateProvider.state('app', {
        url: '',
        abstract:true,
        resolve: {
                init: function($q) {
                    return $q(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('Resolving ...'); // resolve
                            resolve();
                        }, 1000 * 3);
                    });
                }
            },
        template: '<hello-world name="World"></hello-world><div ui-view=""></div>',
    
    
        })
         .state('app.home', {
            url: '/',
            controller: 'HomeCtrl',
            template: '<div class="body">{{content}}</div>',
    
        });
    

    http://plnkr.co/edit/fUnZ2X7TFBzaRno7GSiq?p=preview

    with your expected order :

    Resolving ...
    Initialize hello-world directive.
    Initialize home page.