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){