I'm able to login, logout and display logged in user information from localStorage, however if i logout and login again with different user app displays information of previous user! this should not happen as i can see new user data in localStorage. New data displays correctly if i refresh the page manually!
I need this app to display currently logged in user's data as it's already available in localStorage..
routes.js
angular.module('app.routes', [])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('menu', {
url: '/side-menu',
templateUrl: 'templates/menu.html',
controller: 'menuCtrl'
})
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'loginCtrl'
})
.state('menu.welcome', {
url: '/welcome',
views: {
'side-menu21': {
templateUrl: 'templates/welcome.html',
controller: 'welcomeCtrl'
}
}
})
$urlRouterProvider.otherwise('/user-type')
});
Login:
Here i'm authenticating user through web service, which sends back user object in JSON format which is being stored in localStorage with key 'user' and it works fine.
.controller('loginCtrl', ['$scope', '$stateParams', '$state', '$http',
function ($scope, $stateParams, $state, $http) {
$scope.user = {
username: '',
password: ''
};
$scope.login = function(){
var apiUrl = "...";
return $http.post(apiUrl, $scope.user).then(function(response){
window.localStorage.setItem('user', angular.toJson(response.data));
$state.go('menu.welcome');
});
};
}
])
Logout:
Here i'm logging out user by removing 'user' JSON object from localStorage, and redirecting him back to login state, and it works fine.
.controller('menuCtrl', ['$scope', '$stateParams', '$state',
function ($scope, $stateParams, $state) {
$scope.user = angular.fromJson(window.localStorage.getItem('user'));
$scope.logout = function(){
// here i'm removing user from localStorage
window.localStorage.removeItem('user');
$state.go('login');
};
}
])
Menu:
Here i'm displaying user info which is sent from 'menuCtrl' (it's not updating logged in user's data here even if it's available in localStorage)
<h3 id="menu-heading1" class="left-menu-headings">{{user.first_name}} {{user.last_name}}</h3>
<h4 id="menu-heading2" class="left-menu-headings">{{user.email}}</h4>
I already tried following in logout function with no success:
$window.localStorage.clear();
$ionicHistory.clearCache();
$ionicHistory.clearHistory();
Any idea why it's not displaying current data from localStorage?
Use ion view enter to define your user
$scope.$on( "$ionicView.enter", function( scopes, states ) {
$scope.user = angular.fromJson(localStorage.get("user"));
});
Remove the set from the controller declaration.
This will make the user get loaded each time it enters and not each time the controller gets initialized
I have a wild guess, based on your controller name, that "menuCtl" actually lives through the reloging, so it never gets re-initialized. You should add some console.logs around the
$scope.user = angular.fromJson(window.localStorage.getItem('user'));
To see if it is getting called the 2nd time when you relogin. If not, you may have a number of options to follow, for example, add event listeners to the controllers, and broadcast events on login/logout so that controllers would refresh their scope data.
Use $rootScope:
This problem is mostly due to the menuController being shared by the views and not being reloaded, in such case, you could use $rootScope.user which unlike $scope.user is shared by all your controllers, use as follows:
logout controller
.controller('menuCtrl', ['$scope', '$stateParams', '$state',
function ($scope, $stateParams, $state, $rootScope) { // <-- add $rootScope
// use $rootScope.user instead of $scope.user
$rootScope.user = angular.fromJson(window.localStorage.getItem('user'));
// rest of your code is fine.
$scope.logout = function(){
// here i'm removing user from localStorage
window.localStorage.removeItem('user');
$state.go('login');
};
}
login controller
.controller('loginCtrl', ['$scope', '$stateParams', '$state', '$http',
function ($scope, $stateParams, $state, $http, $rootScope) { // <-- add $rootScope
// $scope.user = { <-- change to $rootScope
$rootScope.user = {
username: '',
password: ''
};
$scope.login = function(){
var apiUrl = "...";
return $http.post(apiUrl, $rootScope.user).then(function(response){
window.localStorage.setItem('user', angular.toJson(response.data));
// update $rootScope.user:
$rootScope.user = angular.fromJson(window.localStorage.getItem('user'));
$state.go('menu.welcome');
});
};
}
])
empty or delete the $scope.user
.controller('menuCtrl', ['$scope', '$stateParams', '$state', '$window',
function ($scope, $stateParams, $state) {
$scope.user = angular.fromJson(window.localStorage.getItem('user'));
$scope.logout = function(){
// here i'm removing user from localStorage
$window.localStorage.removeItem('user');
$state.go('login');
delete $scope.user;
/*or $scope.user = {}*/
};
$scope.login = function(){
var apiUrl = "...";
return $http.post(apiUrl, $rootScope.user).then(function(response){
$window.localStorage.setItem('user', angular.toJson(response.data));
// update $rootScope.user:
$rootScope.user = angular.fromJson($window.localStorage.getItem('user'));
$state.go('menu.welcome');
});
};
}
])
Related
I'm using ionic and angularjs.
My app.
.state('auth', {
url: '/auth',
abstract:true,
templateUrl: 'templates/auth.html',
controller: 'authCtrl'
})
.state('auth.reg', {
url: '/reg',
templateUrl: 'templates/register.html',
controller: 'regCtrl'
});
I have this in my auth.html (root view) :
{{authHeader}}
My controller.js
.controller('authCtrl', function($scope, $stateParams) {
// here can get the scope
// $scope.authHeader = "register";
})
.controller('regCtrl', function($scope, $stateParams) {
// here CAN NOT get the scope
$scope.authHeader = "register";
});
Only in root controller I can get the $scope. I want to add another controller called login, and change there to login. Any idea?
You can use $rootScope for this purpose
.controller('authCtrl', function($scope, $rootScope, $stateParams) {
// here can get the scope
// $rootScope.authHeader = "register";
})
And in reg:
.controller('regCtrl', function($scope, $rootScope, $stateParams) {
// here CAN NOT get the scope
$rootScope.authHeader = "register";
});
You can use $rootScope for this purpose
.controller('authCtrl', function($scope, $rootScope, $stateParams) {
// here can get the scope
// $rootScope.headerData.authHeader = "register";
})
And in reg:
.controller('regCtrl', function($scope, $rootScope, $stateParams) {
// here CAN NOT get the scope
$rootScope.headerData = {authHeader : "register"};
});
In your model please use -
{{headerData.authHeader}}
It will always update when controller change.
Try to introduce a Model (a reference object)
$scope.Model = { authHeader : "register" };
That will be inherited by each sub-state and could be changed
usage would be
// {{authHeader}}
{{Model.authHeader}}
See more details here:
How do I share $scope data between states in angularjs ui-router?
or there
I am trying to redirect a user to different page after user is authenticated. I am using jwt authentication and I tried with $location, $window for redirection but its throwing error $state.go is not a function. I am new to angular and I am guessing there should be way to redirect may using a service in angular but I am still new to factories and service.
I have my state provider like this in state.js file:
myApp.config(function ($stateProvider, $urlRouterProvider) {
// default route
$urlRouterProvider.otherwise("/Home");
var header = {
templateUrl: 'commonViews/Header.html',
controller: function ($scope) {
}
};
var footer = {
templateUrl: 'commonViews/Footer.html',
controller: function ($scope) {
}
};
// ui router states
$stateProvider
.state('Home', {
url: "/Home",
views: {
header: header,
content: {
templateUrl: 'views/HomePage.html',
controller: function ($scope) {
}
},
footer: footer
}
})
.state('LoggedIn', {
url: "/LoggedIn",
views: {
'header': header,
'content': {
templateUrl: 'views/LoggedIn.html',
controller: function () {
}
},
'footer': footer
}
});
});
and loginController.js:
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state)
{
$scope.email = "";
$scope.password = "";
$scope.token = "";
$scope.loginForm = function () {
var data = {email: $scope.email, password: $scope.password};
var url = 'rs/loginResource/login';
$http.post(url, data).then(function (response)
{
$localStorage.token = response.data.token;
console.log("Encoded Token in localstorage is:" + $localStorage.token);
if ($localStorage.token) {
// $location.url("/LoggedIn");
$state.go('/LoggedIn');
}
}, function (error)
{
console.log("error", error);
});
};
}]);
further I have to perform refresh token based on expiration time etc, so is it better to have separate the functions like using a service to do the signup and signin?
The problem is the definition of your controller and the way you're handling your injections. And no, referring to your own answer to your question, the problem is not the "order" of the injections. It's a bit worse.
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state)
in this code you're mapping '$scope' to a $scope variable, '$http' to $http, 'jwtHelper' to jwtHelper, '$localStorage' to $localStorage and '$state' to $sessionStorage, and you're not mapping anything to $state. So obviously you get an error when you try to call a method on an undefined $state variable.
So in short, you're injecting 5 dependencies and you're assigning 6 variables to your dependencies, which in turn results in things not doing what they're supposed to do.
You can use Angular $window:
$window.location.href = '/index.html';
$state. go accepts the view name, not the URL. Replace '/LoggedIn' with Logged and you should be good.
Use $state.go instead of $window and location.
Add $state injector on controller
write code $state.go('LoggedIn');
Instead $state.go('/LoggedIn');
Write state name('LoggedIn') instead of url('/LoggedIn').
Hopefully this will work in your case.
You need to add $window as a dependency to your controller if you are using $window,
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state','$window', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state,$window)
{
$window.location.href = '/index.html';
}
otherwise change the route like this, here also you need to inject $state,
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state','$window','$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state,$window,$state)
{
$state.go('LoggedIn');
}
I have a form in angular, that submits to an API, that returns a 201 status code, and the id and token of the object that was created. My idea is to open up a modal, with that token and show it to the user.
The value of $scope.object.token is updated, but I can't update that state in the view. I tried, $scope.$apply() I get an error $digest already in progress when calling $scope.$apply(). I also tried $timeout() but it doesn't update the view.
controller that handles that behavior is:
angular.module('myApp').controller('ObjectCtrl', ['$scope', 'user', 'object', '$routeParams', '$location', '$uibModal',
function ($scope, user, object, $routeParams, $location, $uibModal, displayToken) {
$scope.object = {
user_id: user.currentUser
}
$scope.create_object = function() {
var promise = object.create($scope.object);
promise.then(function(data){
var token = data.data.token;
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: '/app/views/modal_submit_token.html',
controller: 'ObjectCtrl',
resolve: {
displayToken: function () {
$scope.object.token = token;
}
}
});
});
};
}]);
And on my html,
<p><b>{{ object.token }}</b></p>
To pass the parameter you need to use resolve and inject the items in controller
$scope.Edit = function (Id) {
var modalInstance = $modal.open({
templateUrl: '/app/views/admin/addeditphone.html',
controller: 'EditCtrl',
resolve: {
editId: function () {
return Id;
}
}
});
}
Now if you will use like this:
app.controller('EditCtrl', ['$scope', '$location'
, function ($scope, $location, editId)
in this case editId will be undefined. You need to inject it, like this:
app.controller('EditCtrl', ['$scope', '$location', 'editId'
, function ($scope, $location, editId)
Now it will work smooth, I face the same problem many time, once injected, everything start working!
Font: Pass parameter to modal
I have an Angular service that looks like:
var lunchrServices = angular.module('lunchrServices', []);
lunchrServices.service('authService', function () {
var user = null;
this.login = function (userEmail) {
user = userEmail;
};
this.logout = function () {
user = null;
};
this.currentUser = function(){
return user;
}
});
I use this service on a controller on the main page of my application like so:
var lunchrControllers = angular.module('lunchrControllers', []);
lunchrControllers.controller('MainPageController', ['$scope', '$http', '$state', 'authService',
function ($scope, $http, $state, authService) {
$scope.logIn = function () {
$http.post('/api/users/authenticate', {email: $scope.email, password: $scope.password}).
success(function (data, status, headers, config) {
// lines of interest
authService.login($scope.email);
$state.go('users');
}).
error(function (data, status, headers, config) {
$scope.errorMessages = data;
$scope.password = "";
})
}
}]);
With the users state displaying the following (I'm using ui-router to plug this in a ui-view):
div(class='container')
h1 Welcome {{user}}
// other stuff
The controller for this page looks like:
lunchrControllers.controller('UserController', ['$scope', '$http', '$state', 'authService',
function ($scope, $http, $state, authService) {
$scope.user = authService.currentUser();
//other stuff
}]);
When the user taken to this page through the $state.go('users') call, {{user}} is correctly populated.
The problem, however, is that refreshing the page now results in {{user}} being empty. How can I have the data stored in the service persist through page refreshes?
You can set a cookie or use localStorage. There is a $cookies service in angular.
For a localstorage solution you will have to google around.
shove the user object into a cookie that never expires and then try to read it from there before making your request next time they reload the page.
I have a page with a "status" section for the logged in user where it says "Welcome, [name]", with a "logout" link if they are indeed loggedin.
I'm trying to log them in by setting values on $rootScope from the LoginController and want the "status" section to change, but nothing happens. I have the chrome extension installed and I get see that $rootScope.loggedIn is indeed set to true.
angular.module('pipelineChromeApp')
.controller('LoginController', [
'$rootScope',
'$scope',
'Profile',
'$location',
function ($rootScope, $scope, Profile, $location) {
$scope.apiKey = '';
$scope.error = '';
$scope.login = function(){
$scope.error = '';
var login = Profile.getProfile($scope.apiKey)
login.then(function(resp){
$rootScope.loggedIn = true;
$rootScope.name = resp.data.first_name;
$rootScope.apiKey = resp.data.api_key;
$rootScope.avatar = resp.data.avatar_thumb_url;
// Sets data in localstorage
Profile.login(resp.data);
$location.path( "/actions" );
}, function(error) {
$scope.error = error.data.error;
});
};
}]);
angular.module('pipelineChromeApp')
.controller('StatusController', [
'$rootScope',
'Profile',
'$scope',
'localStorageService',
function ($rootScope, Profile, $scope, localStorageService) {
$scope.loggedIn = $rootScope.loggedIn;
$scope.name = $rootScope.name;
$scope.logout = function() {
Profile.logout()
$location.path("/start");
};
}]);
And the template:
<div class="status" ng-controller="StatusController">
<div ng-if="loggedIn">
Welcome, <span ng-bind="name"></span>!
Logout
</div>
</div>
Looks like I have to use $watch in the $rootScope to updated the local $scope.