AngularJs call a function only after a factory function is called - angularjs

I am trying login user using factory function in angularjs.
This is my code for checking login info:
$scope.login = function(user) {
if(!$rootScope.isLoggedIn) {
LoginService.login($scope.user, $scope);
console.log($rootScope.isLoggedIn);
} else {
$location.path('/home');
}
}
While LoginService factory service look like this:
.factory('LoginService', ['$http', '$location', '$rootScope', function($http,$location, $rootScope) {
return {
login: function(user, scope) {
$rootScope.processGoingOn = true;
var $promise = $http.post('user.php', user);
$promise.then(function(msg) {
var responseData = msg.data;
console.log(responseData);
if(responseData['login_success'] == 'true') {
$rootScope.isLoggedIn = true;
$rootScope.processGoingOn = false;
// success redirect
} else {
$rootScope.isLoggedIn = false;
$rootScope.processGoingOn = false;
// try login again
}
});
}
....
}
});
The change in $rootScope.isLoggedIn is not reflecting back to $scope.login() function in either success or failure, any suggestions?

this is because login function is returned before promise is resolved.
on way to do this can be return $promise like this
login: function(user, scope){
$rootScope.processGoingOn = true;
return $http.post('user.php', user);
}
call then where you have console.log($rootScope.isLoggedIn);

Related

Angularjs, value coming in token from backend not working in client side

What is wrong with the code it's not working, I am trying to request call web service from backend written in spring, the value passing from backend is token wrapped, I am trying to run the code on client side but form is not passing any value.
auth.js
'use strict';
angular. module('app')
.factory('Auth', [ '$http', '$rootScope', '$window', 'Session', 'AUTH_EVENTS',
function($http, $rootScope, $window, Session, AUTH_EVENTS) {
var authService = {};
this.isLoggedIn = function isLoggedIn(){
return session.getUser() !== null;
};
//the login function
authService.login = function(user, success, error) {
$http.post('URL: http://xxx.xxx.x.xx:xxxx/xxxx/authenticateUser').success(function(authData) {
//user is returned with his data from the db
var users = data.users;
if(users[user.username]){
var loginData = users[user.username];
//insert your custom login function here
if(user.username == loginData.username && user.password == loginData.username){
localStorageService.set(['userInfo'],
{ token: result.access_token, userName: loginData.userName });
//delete password no/t to be seen clientside
delete loginData.password;
//update current user into the Session service or $rootScope.currentUser
//whatever you prefer
Session.create(loginData);
//or
$rootScope.currentUser = loginData;
//fire event of successful login
$rootScope.$broadcast(AUTH_EVENTS.loginSuccess);
//run success function
success(loginData);
} else{
//OR ELSE
//unsuccessful login, fire login failed event for
//the according functions to run
$rootScope.$broadcast(AUTH_EVENTS.loginFailed);
error();
}
}
});
};
//check if the user is authenticated
authService.isAuthenticated = function() {
return !!Session.user;
};
//check if the user is authorized to access the next route
//this function can be also used on element level
//e.g. <p ng-if="isAuthorized(authorizedRoles)">show this only to admins</p>
authService.isAuthorized = function(authorizedRoles) {
if (!angular.isArray(authorizedRoles)) {
authorizedRoles = [authorizedRoles];
}
return (authService.isAuthenticated() &&
authorizedRoles.indexOf(Session.userRole) !== -1);
};
//log out the user and broadcast the logoutSuccess event
authService.logout = function(){
Session.destroy();
localStorageService.removeItem("userInfo");
$rootScope.$broadcast(AUTH_EVENTS.logoutSuccess);
}
return authService;
} ]);
authInterceptor
(function () {
'use strict';
var app = angular.module('app');
var factoryId = 'authInterceptor';
app.factory(factoryId, authInterceptor);
authInterceptor.$inject = ['$q', '$location', 'localStorageService', $rootScope, $http];
function authInterceptor($q, $location, localStorageService) {
var service = {
request: request,
responseError: responseError,
};
return service;
function request(config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
function responseError(error) {
var loggedIn = false;
var authData = localStorageService.get('authorizationData');
if (authData) {
loggedIn = true;
}
//We only want to go to the login page if the user is not
//logged in. If the user is logged in and they get a 401 is
//because they don't have access to the resource requested.
if (error.status === 401 && !loggedIn) {
$location.path('/login').replace();
}
return $q.reject(error);
}
}
})();

Angular jwt authentication fails when reloads the page

I'm trying to authenticate user through token. if i login then token will be created and stored in local storage. whenever there is a change in route I'm hitting the api which is built in express js , gives me decoded user value. everything works without refresshing page. Once I refresh the page I'm not able to hit the API. in order to get decoded user value i suppose to click on login button which is there in header , which triggers the route change then again everything works fine. Please help me out .
.controller('mainController', function($rootScope, $location, $window ,Auth){
var vm = this;
$rootScope.loggedIn = Auth.isLoggedIn();
$rootScope.$on('$locationChangeStart', function(){
$rootScope.loggedIn = Auth.isLoggedIn();
Auth.getUser()
.then(function(data){
$rootScope.user = data.data;
});
});
vm.login = function(){
......
}
vm.logout = function(){
......
}
})
Service
.factory('Auth', function($http, $q, AuthToken){
var authFactory = {};
authFactory.login = function(username, password){
return $http.post('/api/login', {
username: username,
password: password
})
.success(function(data){
AuthToken.setToken(data.token);
return data;
});
};
authFactory.logout = function(){
AuthToken.setToken();
};
authFactory.isLoggedIn = function(){
if(AuthToken.getToken()){
return true;
} else {
return false;
}
};
authFactory.getUser = function(){
if(AuthToken.getToken()){
return $http.get('/api/me');
} else {
return $q.reject({ message: "User has no token"});
}
};
return authFactory;
})
factory for setting token and interceptor code
.factory('AuthToken', function($window){
var authTokenFactory = {};
authTokenFactory.getToken = function(){
return $window.localStorage.getItem('token');
};
authTokenFactory.setToken = function(token){
if(token){
$window.localStorage.setItem('token', token);
} else {
$window.localStorage.removeItem('token');
}
};
return authTokenFactory;
})
.factory('AuthInterceptor', function($q, $location, AuthToken){
var interceptorFactory = {};
interceptorFactory.request = function(config){
var token = AuthToken.getToken();
if(token){
config.headers['x-access-token'] = token;
}
return config;
};
interceptorFactory.responseError = function(response){
if(response.status == 403){
$location.path('/login');
}
return $q.reject(response);
};
return interceptorFactory;
});
It may be that you have to reset the $http default headers on refresh. Using cookies in my case, I make a call to the following function at the beginning of $on('$stateChangeStart'):
service.RefreshGlobalVars = function () {
if ($http.defaults.headers.common.RefreshToken == null) {
$http.defaults.headers.common.Authorization = "Bearer " + $cookieStore.get('_Token');
$http.defaults.headers.common.RefreshToken = $cookieStore.get('_RefreshToken');
}
};
edit- to clarify, since I haven't seen your setToken() function, your implementation may vary, but that's pretty much the gist of it.
I got answer, solved it by checking route change in the main app.js, inside run block.
MyApp.run(function ($rootScope, $location, Auth){
$rootScope.loggedIn = Auth.isLoggedIn();
$rootScope.$on('$locationChangeStart', function(){
$rootScope.loggedIn = Auth.isLoggedIn();
Auth.getUser()
.then(function(data){
$rootScope.user = data.data;
});
});

AngularJS Factory im doing it wrong

i am trying to write a Factory for my WebApiCall
so ive written this :
mod.factory('AccountService', function($http) {
var service = {};
var onError = function(response) {
if (response == '') {
return ['Timeout Occured !'];
}
var errors = [];
for (var key in response.ModelState) {
for (var i = 0; i < response.ModelState[key].length; i++) {
errors.push(response.ModelState[key][i]);
}
}
return errors;
};
var onSuccess = function(response) {
return true;
}
service.Login = function(credentials) {
$http.put('http://localhost:9239/Api/Account/', credentials).success(function(data) {
return onSuccess(response);
}).error(function (response) {
return onError(response);
});
};
return service;
});
The Controller :
mod.controller('accountCtrl', function ($scope, $http, $window, $location, ConfigService, AccountService) {
$scope.credentials = { username: '', password: '' };
$scope.Errors = [];
$scope.registerModel = { username: '', password: '', passwordrepeat: '', email: '', emailrepeat: '' };
$scope.isLoading = false;
$scope.Login = function () {
$scope.Errors = [];
$scope.isLoading = true;
AccountService.Login($scope.credentials).onSuccess(function(response) {
$window.sessionStorage.setItem('loginToken', data.SuccessMessages[0]);
if (data.SuccessMessages[1] != '') {
$window.sessionStorage.setItem('groupId', data.SuccessMessages[1]);
}
$scope.isLoading = false;
$location.path('/Home');
}).onError(function(errors) {
$scope.Errors.push(errors);
$scope.isLoading = false;
});
Ok when i Login the Login MEthod is called. But wenn the Success or Error Method from $http is called it doesnt return my onSuccess or onError function.
I think i made some mistakes did i ?
A few things, $http promises don't have onSuccess or onError callbacks, they're sucess and error instead. In your service you are not returning the $http promise, and then you call sucess and error on it, of course it won't work! $http calls, much like Ajax calls anywhere take place asynchronously, meaning that you cant simply return a value in the success/error callback, you can however return a promise:
service.Login = function(credentials) {
return $http.put('http://localhost:9239/Api/Account/', credentials)
};
and in your controller you could use that like:
AccountService.Login($scope.credentials).then(function(data) {//success callback
$window.sessionStorage.setItem('loginToken', data.SuccessMessages[0]);
if (data.SuccessMessages[1] != '') {
$window.sessionStorage.setItem('groupId', data.SuccessMessages[1]);
}
$scope.isLoading = false;
$location.path('/Home');
},function(errors) {//error callback
$scope.Errors.push(errors);
$scope.isLoading = false;
})
when you call then on the promise, it gets executed when the promise is resolved, the first function is success callback and the second is the error callback.

First time injection doesn't instantiate

First time calling, the authenticated property is false, even the credential is OK. If I login once again with the same credential, it will be OK.
Anyway, I am not sure that my factory below is the right way in angularjs or not. Would you please give me any suggestions?
Factory:
app.factory('authenticatorService',['$resource', function($resource){
var authenticator = {};
authenticator.attempt = function(email, password){
var current = this;
$resource("/service/authentication/:id",null,{'update' : { method: 'PUT'}})
.save({'email' : email,'password': password},
//success
function(response){
current.authenticated = sessionStorage.authenticated = true;
current.userinfo = response.user;
current.authenticated = true;
},
function(response){
current.authenticated = false;
}
);
return this.authenticated;
};
authenticator.logout = function(){
delete sessionStorage.authenticated;
this.authenticated = false;
this.userinfo = null;
return true;
};
authenticator.check = function(){
if(this.userinfo && this.authenticated){
return true;
}
return false;
};
return authenticator;
}]);
Controller:
app.controller('authenCtrl',
[
'authenticatorService',
'$scope',
'$sanitize',
'$log',
'$location',
function(alert, authenticator, $scope, $sanitize, $log, $location){
$scope.login = function(){
if(authenticator.attempt($sanitize($scope.email) ,$sanitize($scope.password))){
$location.path('/dashboard');
}else{
alert.add("danger","Login fail.");
}
}
}]);
The this.authenticated in authenticator.attempt will return before the asynchronous call from $resource has completed.
You will need to wait for the promise to be resolved before returning from the factory, and before receiving in the controller.
Something like this should hopefully work:
Factory:
authenticator.attempt = function(email, password){
var current = this;
$resource("/service/authentication/:id", null, {'update' : { method: 'PUT'}})
.save({'email' : email,'password': password},
function(response){
current.authenticated = sessionStorage.authenticated = true;
current.userinfo = response.user;
current.authenticated = true;
},
function(response){
current.authenticated = false;
}
).$promise.then(function () {
return current.authenticated;
});
};
Controller:
$scope.login = function() {
var email = $sanitize($scope.email);
var password = $sanitize($scope.password);
authenticator.attempt(email, password).then(function(isAuthenticated) {
if (isAuthenticated) $location.path('/dashboard');
else alert.add("danger", "Login fail.");
});
};

Angularjs async callback return undefined under $scope.$apply();

This is my factory code. The callback is async so i put it under $rootScope.safeApply().
Then I call console.log(authService.authUser) in my controller but it still return undefined when user logged in. But it is find if user not login and will show 'not login' in console. Any idea?
myapp.factory('authService', ['$rootScope', function($rootScope) {
var auth = {};
$rootScope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
auth.firebaseAuthClient = new FirebaseAuthClient(FIREBASEREF, function(error, user) {
$rootScope.safeApply(function() {
if (user) {
auth.authUser = user;
//auth.isLoggedIn = true;
} else if (error) {
auth.authError = error;
} else {
auth.not = 'not login';
//auth.isLoggedIn = false;
}
});
});
auth.login = function() {
this.firebaseAuthClient.login('facebook');
};
auth.logout = function() {
this.firebaseAuthClient.logout();
};
return auth;
}]);
UPDATED
auth.callback = function(error, user) {
if (user) {
deferred.resolve(user);
} else if (error) {
deferred.reject(error);
} else {
//deferred.reject('not login'); // there is no callback value here
}
return deferred.promise;
}
in controller
callback().then(function(response) {
$scope.isLoggedIn = true;
}, function(response) {
$scope.isLoggedIn = false //How can i set false here?
});
UPDATE 2
Now every thing work fine, I'm able to monitoring user login state. But still having a problem. Check the code below
authService.callback().then(function(success){
$rootScope.isLoggedIn = true; //If promise return success set isLoggedIn true
}, function(fail){
**//If user not login set isLoggedIn false;
//I have problem here because i'm not able to deferred.reject below**
$rootScope.isLoggedIn = false;
})
auth.callback = function(error, user) {
$timeout(function() {
if (user) {
deferred.resolve(user);
} else if (error) {
deferred.reject(error);
} else {
//If this line is added,
//.then() will not return anything not even undefined with no error,
//No mater user logged-in or not login.
//If I comment it out, everything will work fine but how can I
//set isLoggedIn = false?
deferred.reject();
}
}, 0);
return deferred.promise;
}
Wrap the outside service's deferred resolve in a $timeout block to let angular know when its resolved. This way when your controller runs then callback, it'll be in a $digest cycle.
See this fiddle as a working proof of concept: http://jsfiddle.net/Zmetser/rkJKt/
// in controller
authService.login().then(success, error);
// service
myapp.factory('authService', ['$q', '$timeout', function( $q, $timeout ) {
var auth = {},
deferred;
firebaseAuthClient = new FirebaseAuthClient(FIREBASEREF, afterAuth);
function afterAuth( error, user ) {
// Let angular know the deferred has been resolved.
$timeout(function () {
if (user) {
deferred.resolve(user);
} else if (error) {
deferred.reject(error);
} else {
deferred.reject(); // there is no callback value here
}
}, 0);
}
auth.login = function() {
deferred = $q.defer();
firebaseAuthClient.login('facebook');
return deferred.promise;
};
auth.logout = function() {
deferred = $q.defer();
firebaseAuthClient.logout();
return deferred.promise;
};
return auth;
}]);

Resources