I built a simple app with user authentication base on this: link
Basically, I have a userAccountService, responsible for communicating with server and login controller handling the login process.
From other controller I want to check if user is already logged in (to hide LogIn button, and show user profile instead).
So I have a navController
function navCtrl ($scope, $modal, userAccountService) {
$scope.IsUserLoggedIn = function () {
return userAccountService.isUserLoggedIn;
}
}
So in HTML I use this ng-hide="isUserLoggedIn()
my userAccountService:
app.factory('userAccountService', ['$http', '$q', userAccountService]);
function userAccountService($http, $q) {
var service = {
registerUser: registerUser,
loginUser: loginUser,
logOut: logOut,
getValues: getValues,
isUserLoggedIn: false,
accessToken: ""
};
// code ommited
function loginUser(userData) {
var tokenUrl = serverBaseUrl + "/Token";
if (!userData.grant_type) {
userData.grant_type = "password";
}
var deferred = $q.defer();
$http({
method: 'POST',
url: tokenUrl,
data: userData,
})
.success(function (data,status,headers,cfg) {
// save the access_token as this is required for each API call.
accessToken = data.access_token;
isUserLoggedIn = true;
// check the log screen to know currently back from the server when a user log in successfully.
console.log(data);
deferred.resolve(data);
})
.error(function (err, status) {
console.log(err);
deferred.reject(status);
});
return deferred.promise;
}
}
What am I doing wrong? Here's another interesting read I took inspiration from: link
You can't return a variable, but you can return a function, so create a function that returns that variable.
Try something like this, it returns your service object (you might want to put a $watch on it):
Service
function userAccountService($http, $q) {
function getData() {
return service;
}
...
}
Controller
$scope.IsUserLoggedIn = userAccountService.getData().isUserLoggedIn;
Also, you're not correctly updating the state variable from your success callback - you're creating global variables instead of using the service object properties. So, for example:
isUserLoggedIn = true;
should be:
service.isUserLoggedIn = true;
Related
Im writing my first app with Angular and now faced up with the problem... I have address for POST request with authentication token. Something like:
http://example.com/orders?authentication_token=123456
So I need to make ng-submit or ng-click that send that request and get a bunch of items and show them on the page...
Also, I have a body for them:
{
"order": {
"seller_id":84,
"price":123,
"delivary_date":"12-12-2025",
}
}
So, what the best way to do that?
So you will have to make one angular service which would communicate with server and fetch the data and one angular controller which will interact with service to get the data and display over the UI.
Lets say service name is MyService:
app.service('MyService', function($http) {
var params = {}; // some parameters
this.getData = function(successCallback, failureCallback) {
$http.post("URL", params).then(function(data) {
successCallback(data);
}, function(data, status) {
failureCallback(data, status);
});
}
});
Controller name is MyCntrl:
app.controller('MyCntrl', function($scope, MyService) {
function successCallback(data) {
$scope.itemList = data;
}
function failureCallback(data, status) {
$scope.itemList = {};
}
$scope.handleClick = function() {
MyService.getData(successCallback, failureCallback);
}
});
I believe it would help you to resolve your requirement!!!
Assume you have a orderCtrl. ng-click or ng-submit is based on your app requirement. Call the function someFunction() that triggers $http post and you can handle the success and failure response.
app.controller('orderCtrl', function($scope, $http) {
$scope.someFunction = function(){
var data = {}; // prepare your data here.
$http({
method : "POST",
url : "specify your url here",
data : data
}).then(function mySucces(response) {
var response = response.data;
// handle your success here
}, function myError(response) {
// handle the failure here
});
});
});
Note :
If you are using a form and you want to trigger this function after user filling all the information, then use ng-submit. If it is independent then use ng-click.
I'm saying again, it's all depends on what you are doing.
I'm using this tutorial to figure out my authentication system for a web app that I am working on. I'm using ui-router's StateProvider and resolve system to reroute the user to the home page if they attempt to access one of the pages that needs authentication. Everything seems to be working, except that the resolve part doesn't seem to be actually working - i.e. my authenticate returns a rejected promise, yet the page loads like normal, despite the fact that there should be some sort of error because of this. What am I doing wrong?
app.states.js
angular
.module('app')
.config(routeConfig);
/** #ngInject */
function routeConfig($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
// checks if user is logged in or not
// passes back rejected promise if not, resolved promise if true
function authenticated(authFactory, $q) {
var deferred = $q.defer();
authFactory.authenticate()
.then(function(authenticate) {
if (authenticate.data === 'true') {
deferred.resolve();
} else {
deferred.reject();
}
});
return deferred.promise;
}
// every new state that should include a sidebar must have it as a view
$stateProvider
.state('dashboard', {
url: '/dashboard/',
views: {
'sidebar': {
templateUrl: 'app/components/navbar/sidebar.html',
controller: 'SidebarController as vm'
},
'content': {
templateUrl: 'app/components/authenticated/dashboard.html',
controller: 'DashboardController as vm'
}
},
resolve: {
authenticated: authenticated
}
})
app.run.js
function runBlock($rootScope, $log, $state) {
$rootScope.$on('$stateChangeError', function () {
// Redirect user to forbidden page
$state.go('forbidden');
});
}
auth.factory.js
'use strict';
angular
.module('app')
.factory('authFactory', authFactory);
authFactory.$inject = ['$http', '$cookies'];
function authFactory($http, $cookies) {
var _token;
var service = {
authenticate: authenticate
};
return service;
// used to prevent user from accessing pages that they shouldn't have access to
// this is used exclusively in app.routes.js/app.states.js
function authenticate() {
// gets user's token from cookies, if no cookie, _token will be blank and server will return 403
// this part might be redundant with other functions, but I left it in for now just to make sure
if ($cookies.getObject('user')) {
_token = $cookies.getObject('user').token;
} else {
_token = '';
}
var request = $http({
method: 'POST',
url: 'http://localhost:8080/checkToken',
headers: {'x-auth-token': _token},
transformResponse: function(data) {
return data;
}
});
return request;
}
}
You need to place return deferred.promise outside then function, so that promise will get returned properly.
Code
function authenticated(authFactory, $q, $log) {
var deferred = $q.defer();
authFactory.authenticate()
.then(function(authenticate) {
if (authenticate.data === 'true') {
deferred.resolve();
} else {
deferred.reject();
}
});
return deferred.promise; //placed outside function
}
I have a single page angularjs app in which whenever there is a change in route I check the login status of the user by a variable stored in a service(after submitting the login form to server) as per this solution AngularJS- Login and Authentication in each route and controller:
app.run(['$rootScope', '$location', 'Auth', function ($rootScope, $location, Auth) {
$rootScope.$on('$routeChangeStart', function (event) {
if (!Auth.isLoggedIn()) {
console.log('DENY');
event.preventDefault();
$location.path('/login');
}
else {
console.log('ALLOW');
$location.path('/home');
}
});}]);
//service
.factory('Auth', function(){
var user;
return{
setUser : function(aUser){
user = aUser;
},
isLoggedIn : function(){
return(user)? user : false;
}
}
})
The problem is when I reload the whole page(by the refresh button) the variable in the service is lost and user gets redirected to login page even when the user session is still on at the backend.
How can I still manage the variable in the service? I thought of using sessionStorage but does not sound secure enough.
Im my opinion you can choose from 2 ways:
Persist the Data on the server-side via session
Store your data in the localStorage or even better in the window.sessionStorage so a page reload doesn't affect your applicant
Maybe angular-cookies can solve your problem
Try to store your data in $window.localStorage ( angular abstraction over javascript window.localStorage)
for example :
(function () {
angular.module('app').factory('UserIdentity', ['$window', function ($window) {
this.UserName = function () {
return $window.localStorage.getItem("username");
};
this.Token = function () {
return $window.localStorage.getItem("token");
};
this.create = function (token, userName) {
$window.localStorage.setItem("token", token);
$window.localStorage.setItem("username", userName);
};
this.destroy = function () {
$window.localStorage.removeItem("token");
$window.localStorage.removeItem("username");
};
this.isAuthenticated = function () {
var token = $window.localStorage.getItem("token");
return !!token;
}
return this;
}]);
})();
My basic premise is I want to call back to the server to get the logged in user in case someone comes to the site and is still logged in. On the page I want to call this method. Since I am passing the user service to all my controllers I don't know which controller will be in use since I won't know what page they're landing on.
I have the following User Service
app.factory('userService', function ($window) {
var root = {};
root.get_current_user = function(http){
var config = {
params: {}
};
http.post("/api/user/show", null, config)
.success(function(data, status, headers, config) {
if(data.success == true) {
user = data.user;
show_authenticated();
}
});
};
return root;
});
Here is an empty controller I'm trying to inject the service into
app.controller('myResourcesController', function($scope, $http, userService) {
});
So on the top of my index file I want to have something along the lines of
controller.get_current_user();
This will be called from all the pages though so I'm not sure the syntax here. All examples I found related to calling a specific controller, and usually from within another controller. Perhaps this needs to go into my angularjs somewhere and not simply within a script tag on my index page.
You could run factory initialization in run method of your angular application.
https://docs.angularjs.org/guide/module#module-loading-dependencies
E.g.
app.run(['userService', function(userService) {
userService.get_current_user();
}]);
And userService factory should store authenticated user object internaly.
...
if (data.success == true) {
root.user = data.user;
}
...
Then you will be able to use your factory in any controller
app.controller('myController', ['userService', function(userService) {
//alert(userService.user);
}]);
You need to inject $http through the factory constructor function, for firsts
app.factory('userService', function ($window, $http) {
var root = {};
root.get_current_user = function(){
var config = {
params: {}
};
$http.post("/api/user/show", null, config)
.success(function(data, status, headers, config) {
if(data.success == true) {
user = data.user;
show_authenticated();
}
});
};
return root;
});
in your controller you can say
$scope.get_current_user = UserService.get_current_user();
ng attributes in your html if needed. besides this, i am not sure what you need.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I got this angular factory:
var productApp = angular.module('productApp', ['ngRoute', 'LocalStorageModule', 'angularSlideables', 'ui.bootstrap']);
productApp.factory('productFactory', function($http, localStorageService, $q) {
var factory = {};
factory.getProductById = function(prod_id) {
if(prod_id !== '') {
$http({
url: 'rest/message/getProductById/' + prod_id,
method: 'GET'
}).success(function(data, status) {
return data;
}).error(function(data, status){
// do nothing
});
}else {
alert("There was an error while passing the ID. Please refresh the page and try again");
}
}
return factory;
});
Injecting the factory in a controller and calling to the "getProductById" function:
productApp.controller('ModalInstanceCtrl', function ($scope, $modalInstance, productFactory, prodId) {
console.log("this is the prod id " + prodId);
// search product in the database
$scope.prod = productFactory.getProductById(prodId);
console.log($scope.prod);
$scope.ok = function () {
console.log($scope.prodData);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
Now, don't know what's wrong with it... the function RETURNS the data because i did a console.log(data) and saw all the response, but in the controller if i inspect the $scope.prod, it's undefined. It's not returning the data back from the function.
(Just in case you guys ask, the "prodId" in the controller parameter is fine, and retrieving that from another controller)
How can i solve this? :(
Thanks in advance.
The pattern I have used to solve this problem is to pass in the success & error callback functions to the factory... like this:
var productApp = angular.module('productApp', ['ngRoute', 'LocalStorageModule', 'angularSlideables', 'ui.bootstrap']);
productApp.factory('productFactory', function($http, localStorageService, $q) {
var factory = {};
factory.getProductById = function(prod_id, successCallback, errorCallback) {
if(prod_id !== '') {
$http({
url: 'rest/message/getProductById/' + prod_id,
method: 'GET'
})
.success(successCallback)
.error(errroCallback);
} else {
alert("There was an error while passing the ID. Please refresh the page and try again");
}
}
return factory;
});
and then:
productApp.controller('ModalInstanceCtrl', function ($scope, $modalInstance, productFactory, prodId) {
console.log("this is the prod id " + prodId);
// search product in the database
productFactory.getProductById(prodId, function successCallback(data) {
$scope.prod = data;
}, function errorCallback(data, status) {
alert("An error occurred retrieving product. Please refresh the page & try again.");
});
console.log($scope.prod);
$scope.ok = function () {
console.log($scope.prodData);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
By doing it this way instead, you have access to the scope in the controller & can do whatever you need to with the returned data.
Here's what I do. I'm using $resournce instead of $http, but it should be enough to get you going. You may even want to use the $resource since it has the built in fns.
My factory:
.factory('WorkOrder', function($resource){
// $resource Usage: $resource(url[, paramDefaults][, actions]);
return $resource('/controller/get/:id.json', {}, {
/*
* By default, the following actions are returned; modify or add as needed
* { 'get': {method:'GET'},
* 'save': {method:'POST'},
* 'query': {method:'GET', isArray:true},
* 'delete': {method:'DELETE'} };
*/
});
})
My controller:
// get the work order data using the work order id from the tag attribute
var getWO = function() {
WorkOrder.get({woId:$attrs.id},
// success callback
function(response) {
// Assign the work order data to the scope
$scope.WorkOrder = response.WorkOrder;
},
// fail callback
function(response) {
// whatever...
}
);
};
getWO();
I put my success and fail fns in my controller because that's where I most likely know how I want to respond to success or failed calls. I also assign the function to a variable and then call it right after in case I want to include the fn call inside a $timeout or call it elsewhere.
Hope this answers your question.