AngularJS: вызов определенной функции перед любыми контроллерами частичных страниц

Я хочу вызвать определенную функцию: GetSession() в начале загрузки моего приложения. Эта функция вызывает вызов $http и получает токен сеанса: GlobalSessionToken с сервера. Этот токен сеанса затем используется в другой логике контроллеров и извлекает данные с сервера. Я называю это GetSession() в основном контроллере: MasterController в $routeChangeStart, но в качестве его асинхронного вызова мой код продвигается вперед до CustomerController перед ответом $http.

Вот мой код:

var GlobalSessionToken = '';  //will get from server later 

//Define an angular module for our app 
var myApp = angular.module('myApp', ['ngRoute']); 

//Define Routing for app 
myApp.config(['$routeProvider', function ($routeProvider) { 
    $routeProvider. 
      when('/customer', { 
          templateUrl: 'partials/customer.html', 
          controller: 'CustomerController', 
          resolve: { 
            loadData: function($q){ 
                return LoadData2($q,'home'); 
            } 
          } 
      }). 
      otherwise({ 
          redirectTo: '/home'
      }); 
}]); 

//controllers start here and are defined in their each JS file 
var controllers = {}; 

//only master controller is defined in app.js, rest are in separate js files
controllers.MasterController = function($rootScope, $http){
    $rootScope.$on('$routeChangeStart', function(){

        if(GlobalSessionToken == ''){
            GetSession();
        }

        console.log('START');
        $rootScope.loadingView = true;
    });

    $rootScope.$on('$routeChangeError', function(){
        console.log('ERROR');
        $rootScope.loadingView = false;
    });
};

controllers.CustomerController = function ($scope) { 
    if(GlobalSessionToken != ''){
        //do something
    }
} 

//adding the controllers to myApp angularjs app 
myApp.controller(controllers); 
//controllers end here 


function GetSession(){
    $http({
        url: GetSessionTokenWebMethod,
        method: "POST",
        data: "{}",
        headers: { 'Content-Type': 'application/json' }
    }).success(function (data, status, headers, config) {
        GlobalSessionToken = data;
    }).error(function (data, status, headers, config) {
        console.log(data);
    });
}

И мой HTML имеет следующие разделы:

<body ng-app="myApp" ng-controller="MasterController">
    <!--Placeholder for views-->
    <div ng-view="">
    </div>
</body>

Как я могу убедиться, что этот GetSession() всегда вызывается в самом начале запуска моего приложения и до того, как какой-либо другой контроллер вызывает и также вызывается только один раз.

EDIT: таким образом я добавил метод run в соответствии с ответом Максима. Все еще нужно выяснить способ ожидания возврата $http, прежде чем идти вперед с контроллерами.

//Some initializing code before Angular invokes controllers
myApp.run(['$rootScope','$http', '$q', function($rootScope, $http, $q) {
   return GetSession($http, $q);
}]);

function GetSession($http, $q){
    var defer = $q.defer();

    $http({
        url: GetSessionTokenWebMethod,
        method: "POST",
        data: "{}",
        headers: { 'Content-Type': 'application/json' }
    }).success(function (data, status, headers, config) {
        GlobalSessionToken = data;
        defer.resolve('done');
    }).error(function (data, status, headers, config) {
        console.log(data);
        defer.reject();
    });

    return defer.promise;
}

Ответ 1

Вы не можете отложить инициализацию контроллеров.

Вы можете поместить свой код контроллера внутри обратного вызова обетования сеанса:

myApp.factory( 'session', function GetSession($http, $q){
    var defer = $q.defer();

    $http({
        url: GetSessionTokenWebMethod,
        method: "POST",
        data: "{}",
        headers: { 'Content-Type': 'application/json' }
    }).success(function (data, status, headers, config) {
        GlobalSessionToken = data;
        defer.resolve('done');
    }).error(function (data, status, headers, config) {
        console.log(data);
        defer.reject();
    });

    return defer.promise;
} );

myApp.controller( 'ctrl', function($scope,session) {
   session.then( function() {
      //$scope.whatever ...
   } ); 
} );

Альтернатива. Если вы не хотите использовать такие обратные вызовы, у вас может быть синхронный запрос сеанса, но это было бы ужасно.

Ответ 2

Несмотря на то, что некоторые из решений здесь совершенно верны, свойство t20 > определения маршрутов - это путь, на мой взгляд. Написание логики приложения внутри session.then в каждом контроллере слишком много, мы также использовали такой подход в одном из проектов, и я не работал так хорошо.

Самый эффективный способ - отложить создание экземпляра контроллера с помощью resolve, поскольку это встроенное решение. Единственная проблема заключается в том, что вам нужно добавить свойство resolve с похожим кодом для каждого определения маршрута, что приведет к дублированию кода.

Чтобы решить эту проблему, вы можете изменить объекты определения маршрута в вспомогательной функции следующим образом:

function withSession(routeConfig) {
  routeConfig.resolve = routeConfig.resolve || {};

  routeConfig.resolve.session = ['getSessionPromise', function(getSessionPromise) {
     return getSessionPromise();
  }]

  return routeConfig;
} 

И затем, где определите ваши маршруты следующим образом:

$routeProvider.when('/example', withSession({
  templateUrl: 'views/example.html',
  controller: 'ExampleCtrl'
}));

Это одно из многих решений, которые я пробовал и которым больше всего понравилось, поскольку он чист и сух.

Ответ 3

Вы не указали никаких деталей, связанных с GetSession. Для таких сценариев вы должны использовать свойство resolve, определяя свои маршруты в $routeProvider. Я вижу, вы уже используете resolve.

Теперь вы можете обернуть GlobalSessionToken в службу Angular, например GlobalSessionTokenService, и вызвать ее в решении для получения маркера до загрузки маршрута. Как

resolve: { 
            loadData: function($q){ 
                return LoadData2($q,'home'); 
            },
            GlobalSessionToken: function(GlobalSessionTokenService) {
                 return GlobalSessionTokenService.getToken()  //This should return promise
            }
         } 

Затем его можно ввести в контроллер с помощью

controllers.MasterController = function($rootScope, $http,GlobalSessionToken){