I'm using ui-router 1.0.0.X with it's transitions new standart.
My code:
Service for login, save data in storage, determine if it exist and clear
app.factory('AuthService', ['$http', '$cookies', '$rootScope', function ($http, $cookies, $rootScope) { var service = {}; // Authenticates throug a rest service service.authenticate = function (email, password, callback) { $http.post('endPoints/login.php', { email: email, password: password }) .then(function (response) { callback(response); }); }; // Creates a cookie and set the Authorization header service.setCredentials = function (response) { $rootScope.globals = response; $http.defaults.headers.common['Authorization'] = 'Bearer ' + response; $cookies.put('globals', $rootScope.globals); }; // Checks if it's authenticated service.isAuthenticated = function () { console.log("If TRUE callback not worked yet!!",$cookies.get('globals') === undefined); return !($cookies.get('globals') === undefined); }; // Clear credentials when logout service.clearCredentials = function () { $rootScope.globals = undefined; $cookies.remove('globals'); console.log("CLEAN coockies globals",$cookies.get('globals')); $http.defaults.headers.common.Authorization = 'Bearer '; }; return service; } ]);
Configuration and run. There we have transitions methods to work:
angular.module('myApp', ['ui.router', 'ngCookies' ]) .config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) { $urlRouterProvider.otherwise('/resumen'); $stateProvider .state("dashboard", { url: "/dashboard", templateUrl: "partials/dashboard.html", controller: "dashCtrl", data: { authRequired: true } }) .state("login", { url: "/login", templateUrl: "partials/login.html", controller: "loginController" }) }]) .run(['$rootScope', '$transitions', '$state', '$cookies', '$http', 'AuthService', function ($rootScope, $transitions, $state, $cookies, $http, AuthService) { // keep user logged in after page refresh $rootScope.globals = $cookies.get('globals') || {}; $http.defaults.headers.common['Authorization'] = 'Bearer ' + $rootScope.globals; $transitions.onStart({ to: function (state) { return state.data != null && state.data.authRequired === true; } }, function () { console.log("I'm transition.onStart and i'm alive!!!"); if (!AuthService.isAuthenticated()) { return $state.target("autorize"); } }); }]);
In dashboard state i use data to mark the state only accessible if is authenticated. Then, on the .run I use the transitions to check the autheticated state.
my controller. $scope.logIn binded to ng-click directive:
$scope.logIn = function () { AuthService.authenticate($scope.loginInfo.email, $scope.loginInfo.password, function (callback) { console.log("CALLBACK!",callback); //-> callback from server. Always true AuthService.setCredentials(callback); });
}
All this works as expected, but on first ng-click i recieve those:
so, .run method with transitions runs BEFORE ng-click callback from server.
On second ng-click data was already set in previous ng-click server request so everything works FINE!
So, the question is how to avoid those terrible two ng-click calling.
documentation for $transition where i took part of code: http://angular-ui.github.io/ui-router/1.0.0-alpha.1/interfaces/transition.ihookregistry.html
related post: angular ui-router login authentication