AngularJS: appelez une fonction particulière avant tout contrôleur de page partiel

Je souhaite appeler une fonction particulière: GetSession() au début de ma charge d'application. Cette fonction fait un appel $http et obtenez un jeton de session: GlobalSessionToken depuis le serveur. Ce jeton de session est ensuite utilisé dans la logique des autres contrôleurs et récupère les données du serveur. J'ai appelé cette GetSession() dans le contrôleur principal: MasterController dans l'événement $routeChangeStart mais comme un appel asynchrone, mon code avance vers CustomerController avant la réponse $http .

Voici mon code:

 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); }); } 

Et mon HTML comporte les sections suivantes:

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

Comment puis-je m'assurer que GetSession() est toujours appelé dès le début de l'application et avant que tout autre contrôleur n'appelle et ne soit appelé qu'une seule fois.

EDIT: C'est ainsi que j'ai ajouté la méthode run à la réponse de Maxim. Il faut encore trouver un moyen d'attendre jusqu'à $http retours d'appel $http avant d'aller de l'avant avec les contrôleurs.

 //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; } 

Vous ne pouvez pas reporter l'initialisation des contrôleurs.

Vous pouvez placer votre code de contrôleur dans un rappel de promesse de session:

 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 ... } ); } ); 

Alternative : si vous ne souhaitez pas utiliser de tels rappels, vous pourriez avoir votre demande de session synchrone, mais ce serait une chose terrible à faire.

Même si certaines des solutions ici sont parfaitement valides, la resolve propriété de la définition des routes est le chemin à suivre, à mon avis. Écriture de la logique de votre application à l'intérieur de la session.then dans tous les contrôleurs, nous utilisons une telle démarche dans l'un des projets et je n'ai pas très bien fonctionné.

Le moyen le plus efficace est de retarder l'instanciation du contrôleur avec resolve , car c'est une solution intégrée. Le seul problème est que vous devez ajouter une propriété de resolve avec un code similaire pour chaque définition d'itinéraire, ce qui entraîne une duplication de code.

Pour résoudre ce problème, vous pouvez modifier vos objets de définition d'itinéraire dans une fonction helper comme ceci:

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

Et puis, où définissez vos itinéraires comme ceci:

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

C'est l'une des nombreuses solutions que j'ai essayées et les plus aimées, car elles sont propres et secrètes.

Vous n'avez fourni aucun détail relatif à GetSession. Pour des scénarios comme celui-ci, vous devez utiliser la propriété de resolve lors de la définition de vos itinéraires dans $routeProvider . Je vois que vous utilisez la resolve déjà.

Ce que vous pouvez faire maintenant, c'est d'envelopper GlobalSessionToken dans un service Angular comme GlobalSessionTokenService et de l'appeler dans la résolution d'obtenir le jeton avant que la route ne soit chargée. Comme

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

Cela peut alors être injecté dans votre contrôleur avec

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