I have a single-page AngularJS app, working with Express, node.js, and MongoDB via Mongoose. Using Passport for user management/authentication.
I'd like the navbar items to change based on whether a user is logged in or not. I'm having trouble figuring out how to implement it.
I find out if a user is logged in through an http request:
server.js
app.get('/checklogin',function(req,res){
if (req.user)
res.send(true);
else
res.send(false);
On the front end, I have a NavController calling this using Angular's $http service:
NavController.js
angular.module('NavCtrl',[]).controller('NavController',function($scope,$http) {
$scope.loggedIn = false;
$scope.isLoggedIn = function() {
$http.get('/checklogin')
.success(function(data) {
console.log(data);
if (data === true)
$scope.loggedIn = true;
else
$scope.loggedIn = false;
})
.error(function(data) {
console.log('error: ' + data);
});
};
};
In my nav, I am using ng-show and ng-hide to determine which selections should be visible. I am also triggering the isLoggedIn() function when the user clicks on the nav items, checking whether the user is logged in during each click.
index.html
<nav class="navbar navbar-inverse" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="/">Home</a>
</div>
<ul class="nav navbar-nav">
<li ng-hide="loggedIn" ng-click="isLoggedIn()">
Login
</li>
<li ng-hide="loggedIn" ng-click="isLoggedIn()">
Sign up
</li>
<li ng-show="loggedIn" ng-click="logOut(); isLoggedIn()">
Log out
</li>
</ul>
</nav>
Problem
There are other places in my app where the user can log in/out, outside of the scope of the NavController. For instance, there's a login button on the login page, which corresponds to the LoginController. I imagine there's a better way to implement this across my entire app.
How can I 'watch' whether req.user is true on the back end and have my nav items respond accordingly?
you can use $rootScope to share info across the entire app:
.controller('NavController',function($scope,$http, $rootScope) {
$scope.isLoggedIn = function() {
$http.get('/checklogin')
.success(function(data) {
console.log(data);
$rootScope.loggedIn = data;
})
.error(function(data) {
console.log('error: ' + data);
});
};
};
now you can change the value of loggedIn from other places in your app by accessing $rootScope.loggedIn in the same way it is done in the code above.
With that said, you should abstract the relevant code into a service and a directive. This would allow you to have one central place to handle, log in, log out, and the state of $rootScope.loggedIn. If you post the rest of the relevant code I could help you out with a more concrete answer
You can broadcast that event when user logs in successfully. And no need to keep polling your server if user is logged in you can keep a variable in memory that tells if you have a valid session or not. You can use a token-based authentication which is set in the server side:
services.factory('UserService', ['$resource',
function($resource){
// represents guest user - not logged
var user = {
firstName : 'guest',
lastName : 'user',
preferredCurrency : "USD",
shoppingCart : {
totalItems : 0,
total : 0
},
};
var resource = function() {
return $resource('/myapp/rest/user/:id',
{ id: "#id"}
)};
return {
getResource: function() {
return resource;
},
getCurrentUser: function() {
return user;
},
setCurrentUser: function(userObj) {
user = userObj;
},
loadUser: function(id) {
user = resource.get(id);
}
}
}]);
services.factory('AuthService', ['$resource', '$rootScope', '$http', '$location', 'AuthenticationService',
function ($resource, $rootScope, $http, $location, AuthenticationService) {
var authFactory = {
authData: undefined
};
authFactory.getAuthData = function () {
return this.authData;
};
authFactory.setAuthData = function (authData) {
this.authData = {
authId: authData.authId,
authToken: authData.authToken,
authPermission: authData.authPermission
};
// broadcast the event to all interested listeners
$rootScope.$broadcast('authChanged');
};
authFactory.isAuthenticated = function () {
return !angular.isUndefined(this.getAuthData());
};
authFactory.login = function (user, functionObj) {
return AuthenticationService.login(user, functionObj);
};
return authFactory;
}]);
services.factory('AuthenticationService', ['$resource',
function($resource){
return $resource('/myapp/rest/auth/',
{},
{
'login': { method: "POST" }
}
);
}]);
services.factory('authHttpRequestInterceptor', ['$injector',
function ($injector) {
var authHttpRequestInterceptor = {
request: function ($request) {
var authFactory = $injector.get('AuthService');
if (authFactory.isAuthenticated()) {
$request.headers['auth-id'] = authFactory.getAuthData().authId;
$request.headers['auth-token'] = authFactory.getAuthData().authToken;
}
return $request;
}
};
return authHttpRequestInterceptor;
}]);
controller:
controllers.controller('LoginCtrl', ['$scope', '$rootScope', 'AuthService', 'UserService',
function LoginCtrl($scope, $rootScope, AuthService, UserService) {
$scope.login = function () {
AuthService.login($scope.userInfo, function (data) {
AuthService.setAuthData(data);
// set user info on user service to reflect on all UI components
UserService.setCurrentUser(data.user);
$location.path('/home/');
});
};
$scope.isLoggedIn = function () {
return AuthService.isAuthenticated();
}
$scope.user = UserService.getCurrentUser();
}])
You can add user's session data inside the index.html using some templating library like EJS.
Just add ejs middleware:
var ejs = require('ejs');
// Register ejs as .html.
app.engine('.html', ejs.__express);
And then, when returning the index.html render the session data into the response.
res.render( "/index.html", {
session : {
user_data : JSON.stringify(req.user)
}
});
You'll now have access to this data in the index.html, now you need to load it into Angular app.
I used preload-resource example, but you can use your own way.
You can also use $localStorage if you want the login to persist outside of the current session. I've found this library has been super helpful for these types of situations. (https://github.com/grevory/angular-local-storage)
Related
I just started learning the MEAN stack and am trying to build an authentication page from scratch (even though I know I could use the out of the box authentication but am doing this to have a background understanding) but am finding it a bit tricky to update texts on my navbar.
My index.html looks like this;
<nav class="navbar navbar-default navbar-fixed-top" ng-controller="HeadController">
<div class = "container-fluid">
<ul class="nav navbar-nav navbar-right">
<li>{{user.name}}</li>
</ul>
</div>
</nav>
<div class="container" ng-view></div>
My app.js looks like this;
var app = angular.module('app',['ngRoute'])
.service("userService", function () {
this.user = {};
this.getUser = function () {
return this.user;
};
this.setUser = function (user) {
this.user = user;
};
})
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/login', {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl as login'
})
.when('/user/profile',{
templateUrl: 'partials/profile.html',
controller: 'ProfileCtrl as profile'
})
.otherwise({
redirectTo: '/login'
});
}]);
app.controller("HeadController", [
'$scope',
'userService',
function ($scope, userService) {
$scope.user = userService.getUser();
}]);
app.controller("LoginCtrl", [
"$location",
"userFactory",
"userService",
function ($location, userFactory, userService) {
var login = this;
login.user = {
username: '',
password: '',
isRemember: true
};
login.login = function () {
userFactory.login(login.user)
.success(function (user) {
userService.setUser(user);
$location.path("/user/profile");
})
.error(function (err) {
console.log(err);
});
};
}]);
finally, my userFactory.js looks like this;
function login(user) {
return $http({
url: '/api/login/',
method: "POST",
data: user,
headers: {
'Content-Type': 'application/json'
}
});
}
return{login:login};
Whenever I login, I expect {{user.name}} be updated but that doesn't happen. I don't know how to get this done. What can I do to make this happen?
The problem is that userService.setUser(user) replaces the services's reference in memory to the "user" object after the previous user object (and reference in memory) had been bound to the $scope of HeadController. There are few ways to fix this:
1. Mutate (instead of replacing) the original object with setUser:
this.setUser = function(newUserData) {
angular.extend(this.user, newUserData);
};
2. Make a dynamic reference to "name" in your template
<li>{{ userService.getUser().name }}</li>
3. (the preferred choice IMO, although definitely not the easiest to implement) Make custom event handlers in your user service so that when you call setUser, callback "listeners" will get invoked. This would allow you to do something like this in HeadController:
userService.onUserUpdate(function(newUser) {
$scope.user = newUser; // or userService.getUser();
});
and to keep the template/view cleaner and more declarative, the way you currently have it:
<li>{{ user.name }}</li>
This can be implemented like this. In userService add:
var privateUserUpdateListeners = [];
this.onUserUpdate = function(cb)
if (angular.isFunction(cb)) {
privateUserUpdateListeners.push(cb);
// Return a callback that can be used to deregister the listener.
// In production code, you may want to wrap this function
// to ensure that it may only get called once.
return function() {
var index = privateUserUpdateListeners.indexOf(cb);
privateUserUpdateListeners.splice(index, 1);
};
}
};
this.broadcastUserUpdate = function(user) {
privateUserUpdateListeners.forEach(function(cb) {
cb(user);
});
};
Then in setUser you could add a broadcast like:
this.setUser = function(user) {
this.user = user;
this.broadcastUserUpdate(user);
};
That should do the trick.
so I'm trying to pass my mongodb data from state to state using ui-router but having trouble making the links and controller as i'm making an app where users have a profile and are able to click on other people profile to see them. I'm able to get the entire list of users profiles but when click, it doesn't get the data so the user profile is blank.
app.js
angular.module('MyApp', ['ui.router']).config(function($stateProvider, $urlRouterProvider, $authProvider) {
/**
* App routes
*/
$stateProvider
.state('home', {
url: '/',
controller: 'HomeCtrl',
templateUrl: 'partials/home.html'
})
.state('about', {
url: '/about',
templateUrl: 'partials/about.html'
})
.state('match', {
url: '/match',
controller: 'matchCtrl',
templateUrl: 'partials/match.html'
})
.state('match.list', {
url: '/list',
controller: 'matchCtrl',
templateUrl: 'partials/match.list.html'
})
//this part is where I need help on most with the controller as it is not working
.state('match.profile', {
url: '/:displayName',
templateUrl: 'partials/match.profile.html',
controller: function($scope, $stateParams) {
$scope.user = $scope.getUserProfile[$stateParams.displayName];
}
});
$urlRouterProvider.otherwise('/');
account.js
angular.module('MyApp').factory('Account',function($http,$stateParams) {
return {
getProfile: function() {
return $http.get('/api/me/:id');
},
getAllProfile: function() {
return $http.get('/api/me');
},
getUserProfile: function() {
return $http.get('/api/me' + $stateParams.displayName);
},
updateProfile: function(profileData) {
return $http.put('/api/me/:id', profileData);
}
};
});
this part works where the mongodb data shows up on the list of users
match.list.html
<div ng-repeat="user in user">
<div class="col-xs-12 col-sm-6 col-md-6">
<div class="well well-sm">
<div class="row">
<h1>{{user.displayName}}</h1>
<h1>{{user.age}} </h1>
<a ng-href="#/match/{{user.displayName}}">
See {{user.displayName}}!
</a>
</div>
</div>
</div>
</div>
the profile part doesn't work as clicking on the a ng-href only lead to a blank profile without data.
match.profile.html
<h1>{{user.displayName}}</h1>
<h1>{{user.age}}</h1>
etc...
how would I go about fixing this so when i click on a user profile using ng-href on the list part. It go to the user profile with the data? Are there any examples that I find similar to this problem with ui-router?
edit
does it have something to do with my controller?
match.js
angular.module('MyApp')
.controller('matchCtrl', function($scope, toastr, Account) {
// set up the filter
$scope.sortUser = 'displayName';
$scope.sortReverse = false;
$scope.searchUser = '';
// get all of the users
$scope.getAllProfile = function () {
Account.getAllProfile()
.then(function (response) {
$scope.user = response.data;
})
.catch(function (response) {
toastr.error(response.data.message, response.status);
});
};
$scope.getUserProfile = function () {
Account.getUserProfile()
.then(function(response) {
$scope.user = response.data;
})
.catch(function (response) {
toastr.error(response.data.message, response.status);
});
};
// get the users
$scope.getAllProfile();
$scope.getUserProfile();
});
the rest api i'm using on node
app.get('/api/me/', function(req, res) {
User.find(function(err, user) {
res.send(user);
});
});
app.get('/api/me/:id', ensureAuthenticated, function(req, res) {
User.findById(req.user, function(err, user) {
res.send(user);
});
});
app.put('/api/me/:id', ensureAuthenticated, function(req, res) {
User.findById(req.user, function(err, user) {
if (!user) {
return res.status(400).send({ message: 'User not found' });
}
user.picture = req.body.picture || user.picture;
user.displayName = req.body.displayName || user.displayName;
user.email = req.body.email || user.email;
user.save(function(err) {
res.status(200).end();
});
});
});
Your match.profile controller is never resolving the promise that's returned from the API by getUserProfile, which is why the UI is blank.
First off, the controller needs the Account service injected into it, as others have noted. The getUserProfile method needs to be called correctly (use () instead of []).
controller: function($scope, $stateParams, Account) {
$scope.user = Account.getUserProfile($stateParams.displayName);
}
I'm also not sure that defining your Account factory to rely on $stateParams is going to work properly, since a factory is a singleton and $stateParams may not update properly as you change states; you'd have to check your Network tab in developer tools to ensure the API endpoint is being built correctly (or just log $stateParams inside the getUserProfile method). I think the better option though would be to take in the url variable as an argument. You're trying to pass it in anyway, but the method isn't expecting any arguments.
getUserProfile: function(displayName) {
return $http.get('/api/me' + displayName);
}
So finally, your controller should look like this
controller: function($scope, $stateParams, Account) {
Account.getUserProfile($stateParams.displayName)
.then(function (profile) {
$scope.user = profile;
});
}
A few other tips with UI-Router
With UI-Router, you should be concerned primarily with states of the application, not URLs. The correct way to transition between states in UI-Router then is to use ui-sref instead of ng-href. Note that ui-sref takes a state name, not a url, so instead of <a ng-href="#/match/{{user.displayName}}">, it'd be better to do <a ui-sref='match.profile({displayName: user.displayName})'> (note how you can still pass in your displayName variable to the $stateParams as an argument.
Your match.profile state is a perfect use case for a resolve function. Resolve functions allow you to load data before the state loads. This ensures that your data is always available to your state before the UI ever renders.
.state('match.profile', {
url: '/:displayName',
templateUrl: 'partials/match.profile.html',
resolve: {
profile: function ($stateParams, Account) {
return Account.getUserProfile($stateParams.displayName)
.then(function (profile) {
return profile;
});
}
},
controller: function($scope, profile) {
$scope.user = profile;
}
});
Notice how you can name the resolve function to be whatever you want, in this case profile. You can inject this directly into your controller and know for certain that your data will already be available to the UI as soon as the controller loads. No loading data, no resolving promises. This is much closer to the proper separation of concerns for a controller in the MVC architecture of Angular where a controller should not be concerned with loading its own data.
You aren't calling method correctly getUserProfile, It not available there in $scope, you have to call it from Account service. Method call happens by parenthesis () not like []. Next thing is, you can get data from getUserProfile method by putting .then function over it.
Code
.state('match.profile', {
url: '/:displayName',
templateUrl: 'partials/match.profile.html',
controller: function($scope, $stateParams, Account) {
Account.getUserProfile($stateParams.displayName)
.then(function(res){
var data = res.data;
$scope.user = data;
}, function(error){
console.log(error);
});
}
});
getUserProfile is a method in Account service. You have used
$scope.getUserProfile[$stateParams.displayName]
Change it to
Account.getUserProfile($stateParams.displayName);
It looks something like this
.state('match.profile', {
url: '/:displayName',
templateUrl: 'partials/match.profile.html',
controller: function($scope, $stateParams, Account) {
$scope.user = Account.getUserProfile[$stateParams.displayName];
}
});
and you have missed a slash in getUserProfile function:
getUserProfile: function() {
return $http.get('/api/me' + $stateParams.displayName);
},
which should be
getUserProfile: function(){
return $http.get('/api/me/' + $stateParams.displayName).then(function(res){
return res.data;
});
}
This is my LoginController, as you can see I have injected the LoginService, I can't seem to figure out why I am getting the error mentioned above (Note: I've made the project modular by breaking my project in separates folder, using gulp and browserify to bundle everything into one file)
'use strict';
function LoginController($scope, $ionicModal, $timeout, $location,
$ionicLoading, $ionicPopup, LoginService) {
// With the new view caching in Ionic, Controllers are only called
// when they are recreated or on app start, instead of every page change.
// To listen for when this page is active (for example, to refresh data),
// listen for the $ionicView.enter event:
//$scope.$on('$ionicView.enter', function(e) {
//});
// Form data for the login modal
$scope.loginData = {};
// Create the login modal that we will use later
$ionicModal.fromTemplateUrl('js/modules/login/login.html', {
scope: $scope
}).then(function(modal) {
$scope.modal = modal;
});
// Triggered in the login modal to close it
$scope.closeLogin = function() {
$scope.modal.hide();
};
// Open the login modal
$scope.login = function() {
$scope.modal.show();
};
$scope.show = function() {
$ionicLoading.show({
template:'<p>Loading...</p><ion-spinner></ion-spinner>'
});
};
$scope.hide = function(){
$ionicLoading.hide();
};
// Perform the login action when the user submits the login form
$scope.doLogin = function() {
console.log('Doing login', $scope.loginData);
// Start showing the progress
$scope.show($ionicLoading);
// Do the call to a service using $http or directly do the call here
LoginService.login($scope.loginData).success(function(data) {
// Do something on success for example if you are doing a login
console.log('Login successful', data);
}).error(function(data) {
// Do something on error
console.log('Login failed', data);
}).finally(function($ionicLoading) {
// On both cases hide the loading
console.log('Hide');
$scope.hide($ionicLoading);
});
};
}
module.exports = ['$scope', '$ionicModal', '$timeout','$location',
'$ionicLoading','LoginService','$ionicPopup',
LoginController];
This is my LoginService file, this is very weird to me because I've injected the appropriate file but yet I keep getting the error mentioned above. Any help or guidance would deeply be appreciated.
'use strict';
function LoginService($http, $q, API_ENDPOINT) {
var BASE_URL = API_ENDPOINT.url;
var LOCAL_TOKEN_KEY = 'yourTokenKey';
var isAuthenticated = false;
var authToken;
function storeUserCredentials(token) {
window.localStorage.setItem(LOCAL_TOKEN_KEY, token);
useCredentials(token);
}
function useCredentials(token) {
isAuthenticated = true;
authToken = token;
// Set the token as header for your requests!x-access-token'
$http.defaults.headers.common.Authorization = authToken;
}
var login = function(user) {
return $q(function(resolve, reject) {
$http.post(BASE_URL + '/authenticate', user).then(function(result){
if (result.data.success) {
storeUserCredentials(result.data.token);
resolve(result.data.msg);
}else{
reject(result.data.msg);
}
});
});
};
return {
login: login,
isAuthenticated: function() {return isAuthenticated;},
};
}
module.exports = ['$http', '$q', 'API_ENDPOINT', LoginService];
This is my login.js file in the same directory as the one posted above
'use strict';
module.exports = angular.module('login', [])
.factory('LoginService', require('./login-service'))
.controller('LoginController', require('./login-controller'));
You should first do require and then only define the service. Since you are directly passing require in the .factory('LoginServie, require()` the service name is getting registered but its body is empty.
I've not worked much with require but here is you can try:
require('./login-service');
module.exports = angular.module('login', [])
// Make this code synchornous that this should only run when above require loaded the script
.factory('LoginService', LoginService)
.controller('LoginController', require('./login-controller'));
Or (probably)
require('./login-service', function() {
module.exports = angular.module('login', [])
.factory('LoginService', LoginService)
.controller('LoginController', require('./login-controller'));
})
When using a factory you are getting the actual class, and you need to instantiate it. When using a service you get an instance of the service. Take a look at the following example: AngularJS : Factory and Service?
I am trying to retain the user information when page refresh. I used cookieStore for this purpose. So my run module in the Angular App looks like this.
.run(['$rootScope', '$cookieStore', '$state', function($rootScope, $cookieStore, $state) {
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, $location){
var requireLogin = toState.data.requireLogin;
if(typeof $rootScope.user == 'undefined'){
$rootScope.user=$cookieStore.get("user");
$rootScope.sessionid=$cookieStore.get("session");
}
if(requireLogin && typeof $rootScope.user === 'undefined'){
event.preventDefault();
$state.go('login', null, {notify: false}).then(function(state) {
$rootScope.$broadcast('$stateChangeSuccess', state, null);
});
}
});
Two main things I wanted to achieve from this is,
Have to get the user and sessioninfo from the browser's local storage, when page refresh.
If user is undefined, then it has to be redirected to the login page. It is for restricting the users to go to intermediate pages without login.
If user is undefined, and data is not available in the local storage, the first if statement gives error and the second if statement doesnot work.
So when the user tries to visit any page the first time without going to login page, it is not redirecting to the login page, because the code failed in first if statement, the second if not working.
How can I achieve both the functionalities together?
Thank you
You can create an authInterceptor factory and push it in interceptors.
This method will always check if user is logged in or not on each page and will throw user on login page if he is not authenticated
For purposes of global error handling, authentication, or any kind of
synchronous or asynchronous pre-processing of request or
postprocessing of responses, it is desirable to be able to intercept
requests before they are handed to the server and responses before
they are handed over to the application code that initiated these
requests. The interceptors leverage the promise APIs to fulfill this need for >both synchronous and asynchronous pre-processing.
Learn more about Interceptors
'use strict';
angular.module('app', [
'ngCookies',
'ngResource',
'ngSanitize',
'ngRoute'
])
.config(function($routeProvider, $locationProvider, $httpProvider) {
$routeProvider
.otherwise({
redirectTo: '/'
});
$httpProvider.interceptors.push('authInterceptor');
})
.factory('authInterceptor', function($rootScope, $q, $cookieStore, $location) {
return {
// Add authorization token to headers
request: function(config) {
config.headers = config.headers || {};
if ($cookieStore.get('token')) {
config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
}
return config;
},
// Intercept 401s and redirect you to login
responseError: function(response) {
if (response.status === 401) {
$location.path('/login');
// remove any stale tokens
$cookieStore.remove('token');
return $q.reject(response);
} else {
return $q.reject(response);
}
}
};
})
.run(function($rootScope, $location, Auth) {
// Redirect to login if route requires auth and you're not logged in
$rootScope.$on('$routeChangeStart', function(event, next) {
Auth.isLoggedInAsync(function(loggedIn) {
if (next.authenticate && !loggedIn) {
$location.path('/login');
}
});
});
})
.factory('Auth', function Auth($location, $rootScope, $http, User, $cookieStore, $q) {
var currentUser = {};
if ($cookieStore.get('token')) {
currentUser = User.get();
}
return {
/**
* Gets all available info on authenticated user
*
* #return {Object} user
*/
getCurrentUser: function() {
return currentUser;
},
/**
* Check if a user is logged in
*
* #return {Boolean}
*/
isLoggedIn: function() {
return currentUser.hasOwnProperty('role');
},
/**
* Waits for currentUser to resolve before checking if user is logged in
*/
isLoggedInAsync: function(cb) {
if (currentUser.hasOwnProperty('$promise')) {
currentUser.$promise.then(function() {
cb(true);
}).catch(function() {
cb(false);
});
} else if (currentUser.hasOwnProperty('role')) {
cb(true);
} else {
cb(false);
}
}
};
})
.factory('User', function($resource) {
return $resource('/api/users/:id/:controller', {
id: '#_id'
}
});
});
With Above Mechanism, you can use Auth service to get user info in any controller or directives as:
.controller('MainCtrl', function ($scope, Auth) {
$scope.currentUser = Auth.getCurrentUser;
});
in template file:
<div ng-controller="MainCtrl">
<p> Hi {{currentUser().name}}!</p>
</div>
Note: You need to create a proper REST API in order to get correct user data
I would look into using ngStorage. I use the sessionStorage object which will retain the data even on refresh. If you need further implentation example please let me know but the documentation is great.
https://github.com/gsklee/ngStorage
I have an application where the frontend is build on AngularJS and backend is on laravel 5.1.
The user authentication is done by account controller via an API call:
myApp.controller('LoginCtrl', function($scope,$auth,$location){
$scope.authenticate = function(provider){
$auth.authenticate(provider)
.then(function() {
toastr.success('You have successfully signed in with ' + provider);
$location.path('/');
})
.catch(function(response) {
toastr.error(response.data.message);
});
};
});
angular.module('MyApp')
.factory('Account', function($http){
return {
getProfile: function(){
return $http.get('/api/me');
}
}
});
Once authenticated, the function getProfile is called to populate user data into the view by controller:
myApp.controller('UserApiCtrl', function($scope,$auth,Account){
$scope.user = {};
$scope.getProfile = function(){
Account.getProfile()
.then(function(response){
$scope.user = response.data;
})
.catch(function(response){
})
};
$scope.getProfile();
})
For the page to able render user data across all the different controller, should I assign user data with just $scope or assign it to $rootScope in app.js where user data will be available globally.
You could use $cookies ("Provides read/write access to browser's cookies.")
myApp.controller('UserApiCtrl', function($scope,$auth,Account,Auth,$cookies){
$scope.user = {};
$scope.getProfile = function(){
Account.getProfile()
.then(function(response){
$cookies.putObject('user', response.data);
})
.catch(function(response){
if(response.status === 401)
$cookies.remove('user');
})
};
$scope.getProfile();
})
Example service:
myApp.factory('Auth', ['$rootScope', '$cookies', function($rootScope, $cookies) {
$rootScope.user = $cookies.getObject('user') || {
id: '',
token: ''
};
...
I've used a controller on my body tag to provide access to more global stuff and then controllers in my individual views to do things that are more specific to the view.
<body ng-controller = "appController as app">
<div ui-view></div>
</body>
This just seems cleaner than using $rootScope to me.