I have an AngularJS app which communicates with a Laravel PHP backend. Sending a GET request to /api/checkLogin
will return { logged: false, username: undefined, id: undefined }
if the user is not logged in, otherwise, it will return something like { logged: true, username: 'John', id: 123 }
.
I am not too familiar with using AngularJS services, but I would like to set up a service called AuthService
that can, well, perform my app's authentication services.
I would like to implement the following functions: AuthService.loggedIn
, AuthService.isAdmin
, AuthService.username
, and AuthService.id
.
I want these functions implemented in such a way that calling one will set the values for all the rest. For example, let's say I call AuthService.isAdmin
. This function will check if isAdmin
is set, if so, it will return the value of isAdmin
. If isAdmin
is not set, it will make an HTTP request to /api/checkLogin
, set the values for loggedIn
, isAdmin
, username
, and id
, and then return the value of isAdmin
. How can I accomplish this?
Here is the service I have tried putting together:
angular.module('myApp').factory('AuthService', ['$http', function($http) {
var loggedIn;
var isAdmin;
var username;
var id;
var checkLogin = function() {
if(loggedIn != undefined) {
return loggedIn
} else {
setUserData(checkLogin);
}
}
var checkAdmin = function() {
if(isAdmin != undefined) {
return isAdmin
} else {
setUserData(checkLogin);
}
}
var returnUsername = function() {
if(username != undefined) {
return username
} else {
setUserData(checkLogin);
}
}
var returnId = function() {
if(id != undefined) {
return id
} else {
setUserData(checkLogin);
}
}
// Our function call which will set our loggedIn, isAdmin, username, and id values
var setUserData = function(callback) {
$http.get(baseURL+'/api/checkLogin').success(function(data) {
loggedIn = data.logged;
if(loggedIn) {
isAdmin = data.is_admin;
username = data.username;
id = data.id;
}
callback();
});
}
return {
loggedIn: function() { return checkLogin(); },
isAdmin: function() { return checkAdmin(); },
username: function() { return returnUsername(); },
id: function() { return returnId(); },
}
}]);
It looks you want to use checkLogin
as a callback, but instead of doing it the way you have it, return the promise back to checkLogin
from setUserData
. Then in checkLogin
, create your own deferred to handle the results.
You are acting on asynchronous logic by introducing the $http
call, so checkLogin
is going to need to return a promise in all cases:
var checkLogin = function() {
// Create a custom deferred
var defer = $q.defer();
if(loggedIn != undefined) {
// Resolve your deferred with the value of logged in
defer.resolve(loggedIn);
} else {
setUserData().then(function (data) {
console.log('Set user data returned successfully');
loggedIn = data.logged;
if(loggedIn) {
isAdmin = data.is_admin;
username = data.username;
id = data.id;
defer.resolve(loggedIn);
} else {
defer.reject();
}
}, function () {
console.log('setUserData failed');
defer.reject();
});
}
return defer.promise;
}
var setUserData = function() {
return $http.get(baseURL+'/api/checkLogin');
}
AuthService.loggedIn()
will now return a promise. You have to resolve the promise to get the value out of it:
AuthService.loggedIn().then(function (data) {
console.log(data);
});
The function passed to then above will be called when the promise is resolved with the value that the promise was resolved with. In this case, its the value of data.logged
because thats what was passed to defer.resolve
in your checkLogin
function.
Here's some reading on Promises:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise