Reputation: 5460
A bit of info. I'm working on a single page app, but am attempting to make it just an HTML file, rather than an actual dynamic page that contains all the bootstrap information in it. I'm also hoping to, when the app boots (or perhaps prior to), check to see if the current session is 'logged in', and if not then direct the hash to the 'login'.
I'm new to Angular, and am having a difficult time figuring out how to program out this flow. So, in essence..
Any pointers on where #2 and #3 would live? In my 'easy world' I'd just use jquery to grab that data, and then call the angular.resumeBootstrap([appname])
. But, as I'm trying to actually learn Angular rather than just hack around the parts I don't understand, I'd like to know what would be used in this place. I was looking at providers, but I'm not sure that's what I need.
Thanks!
Based on @Mik378's answer, I've updated my code to the following as a test. It works to a point, but as the 'get' is async, it allows the application to continue loading whatever it was before then shooting off the status results..
var app = angular.module('ping', [
'ngRoute',
'ping.controllers'
]).provider('security', function() {
this.$get = ['$http', function($http) {
var service = {
getLoginStatus: function () {
if (service.isAuthenticated())
return $q.when(service.currentUser);
else
return $http.get('/login/status').then(function (response) {
console.log(response);
service.loggedIn = response.data.loggedIn;
console.log(service);
return service.currentUser;
});
},
isAuthenticated: function () {
return !!service.loggedIn;
}
};
return service;
}];
}).run(['security', function(security) {
return security.getLoginStatus().then(function () {
if(!security.isAuthenticated()) {
console.log("BADNESS");
} else {
console.log("GOODNESS");
}
});
}]);
My hope was that this could somehow be completed prior to the first controller booting up so that it wasn't loading (or attempting to load) things that weren't even cleared for access yet.
I started looking into the 'resolve' property in the router, and @Mik378 verified what I was looking at. My final code that is (currently) working how I want it is as follows (appologies about the super long code block)
angular.module('ping.controllers', [])
.controller('Dashboard', ['$scope', function($scope) {
console.log('dashboard')
}])
.controller('Login', ['$scope', function($scope) {
console.log('login')
}]);
var app = angular.module('ping', [
'ngRoute',
'ping.controllers'
]).run(['$rootScope', '$location', function($root, $location) {
$root.$on("$routeChangeError", function (event, current, previous, rejection) {
switch(rejection) {
case "not logged in":
$location.path("/login"); //<-- NOTE #1
break;
}
});
}]);
app.provider('loginSecurity', function() {
this.$get = ['$http', '$q', function($http, $q) {
var service = {
defer: $q.defer, //<-- NOTE #2
requireAuth: function() { //<-- NOTE #3
var deferred = service.defer();
service.getLoginStatus().then(function() {
if (!service.isAuthenticated()) {
deferred.reject("not logged in")
} else {
deferred.resolve("Auth OK")
}
});
return deferred.promise;
},
getLoginStatus: function() {
if (service.isAuthenticated()) {
return $q.when(service.currentUser);
} else {
return $http.get('/login/status').then(function(response) {
console.log(response);
service.loggedIn = response.data.loggedIn;
console.log(service);
return service.currentUser;
});
}
},
isAuthenticated: function() {
return !!service.loggedIn;
}
};
return service;
}
];
});
app.config(['$routeProvider', function($routeProvider) {
console.log('Routing loading');
$routeProvider.when('/', {
templateUrl: 'static/scripts/dashboard/template.html',
controller: 'Dashboard',
resolve: {'loginSecurity': function (loginSecurity) {
return loginSecurity.requireAuth(); //<- NOTE #4
}}
});
$routeProvider.when('/login', {
templateUrl: 'static/scripts/login/template.html',
controller: 'Login'
});
$routeProvider.otherwise({redirectTo: '/404'});
}]);
Notes:
Whew. I think that's enough for a day. Time for a beer.
Upvotes: 4
Views: 413
Reputation: 22191
No need to use a deferred bootstrap for your case:
angular.module('app').run(['security', '$location', function(security) {
// Get the current user when the application starts
// (in case they are still logged in from a previous session)
security.requestCurrentUser().then(function(){
if(!security.isAuthenticated())
$location.path('yourPathToLoginPage')
}; //service returning the current user, if already logged in
}]);
this method requestCurrentUser
would be the following:
requestCurrentUser: function () {
if (service.isAuthenticated())
return $q.when(service.currentUser);
else
return $http.get('/api/current-user').then(function (response) {
service.currentUser = response.data.user;
return service.currentUser;
});
}
and inside security
service again:
isAuthenticated: function () {
return !!service.currentUser;
}
Note the run
method of the module => As soon as the application runs, this service is called.
To prevent any controller to be initialized before the promise provided by requestCurrentUser
is resolved, a better solution, as evoked in the comments below, is to use the resolve
route property .
Upvotes: 2