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.
Related
I tried to put a $ state.reload in my controller after a POST request, but it does not refresh my page. Therefore, after I register my form, the data is not updated on my page .. I am obliged to refresh manually so that it shows me the right data.
.controller('editCtrl', function($scope, $stateParams, $state, AppService) {
$scope.infos = AppService.getObject();
console.log($scope.infos);
AppService.user($scope.infos).then(function(response){
$scope.user = response;
console.log($scope.user);
});
$scope.save = function (currObj) {
AppService.edituser($scope.form,$scope.infos).then(function(response){
AppService.addObject(currObj);
console.log(currObj);
$state.reload('menu.infosUser');
$ionicLoading.hide();
$state.go('menu.infosUser',{reload: true});
});
};
})
I will reply as soon as possible to all proposals :)
If you really want to reload your page then use location.reload() for reloading the page like
.controller('editCtrl', function($scope, $stateParams, $state, AppService) {
$scope.infos = AppService.getObject();
console.log($scope.infos);
AppService.user($scope.infos).then(function(response){
$scope.user = response;
console.log($scope.user);
});
$scope.save = function (currObj) {
AppService.edituser($scope.form,$scope.infos).then(function(response){
AppService.addObject(currObj);
console.log(currObj);
location.reload();
});
};
})
Or you can reload your state by using only $state.go('menu.infosUser',{reload: true});, it will clear your cached data, Eg
.controller('editCtrl', function($scope, $stateParams, $state, AppService) {
$scope.infos = AppService.getObject();
console.log($scope.infos);
AppService.user($scope.infos).then(function(response){
$scope.user = response;
console.log($scope.user);
});
$scope.save = function (currObj) {
AppService.edituser($scope.form,$scope.infos).then(function(response){
AppService.addObject(currObj);
console.log(currObj);
$ionicLoading.hide();
$state.go('menu.infosUser',{reload: true});
});
};
})
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');
});
};
}
])
I want to pass the data in $rootScope of users
Here is my factroty
userProvider.js
'use strict';
app
.factory('userProvider', function ($rootScope , $http , $location) {
var url='http://127.0.0.1:100/suitecrm/API/Login.php';
function logIn(user) {
$http.post(url,user)
.success(function (response) {
$rootScope.user=response.data;
$location.path('/profile');
console.log(response);
});
}
return {
logIn: logIn
}
});
console.log(response); show me data normally in the console
Here is the controller of the profile which i want to show information of current user
'use strict';
app
.controller('Profile', function ($scope ,userProvider, $rootScope) {
console.log($rootScope.user);
})
;
But in the console of chrome shows me undefined.
Here is Routing.js
'use strict';
var cacheActive=false;
app.config(function ($stateProvider) {
$stateProvider
.state('homapage', {
cache: cacheActive,
url: '/login',
templateUrl: 'js/views/homepage/Login.html',
controller:'homepageLogin'
})
.state('profile', {
cache: cacheActive,
url:'/profile',
templateUrl:'js/views/profiles/profile.html',
controller:'profile'
})
});
How can i pass the data in $rootScope and show them in the view of the controller?
Thank u
You haven't called the logIn() function from your userProvider service yet.
app
.controller('Profile', function ($scope ,userProvider, $rootScope) {
userProvider.logIn($scope.user);
console.log($rootScope.user);
})
But,
I suggest you do it without using $rootScope. What you can is from your factory, you may want to return the data after the call:
app.
factory('userProvider', function($http){
var url = 'http://127.0.0.1:100/suitecrm/API/Login.php';
function logIn(user) {
$http.post(url,user).success(function (response) {
return response;
});
}
return {
logIn: logIn
}
})
Then, again, without using $rootScope, on your Profile controller you can do:
app.
controller('Profile', function($scope, userProvider){
$scope.user = {...}
$scope.currentUser = userProvider.logIn($scope.user);
console.log($scope.currentUser)
})
For the location routing, please do it inside your controller, instead of the factory.
I have a login controller
myApp.controller('LoginCtrl', ['$scope', '$http','$location', function($scope, $http, $location) {
$scope.login = function() {
var data = JSON.stringify({user: $scope.user.id, password: $scope.user.password, type: "m.login.password"});
$http.post("http://localhost:8008/_matrix/client/api/v1/login", data).then(function mySuccess(details){
$http.post('/login',details.data).success(function(response){
console.log(response);
});
$location.path('home');
}, function myError(err) {
console.log(err);
alert("Invalid username/password")
});
};
}]);
and a home controller
myApp.controller('HomeCtrl', ['$scope', '$http','$location', function($scope, $http, $location) {
console.log("Hello World from home controller");
var refresh = function() {
$http.get('/roomNames').success(function(response) {
console.log("I got the data I requested");
$scope.roomNames = response;
});
}
refresh();
}]);
As seen, if the login details are correct, the LoginCtrl changes the route to be home.html.
However, when I run the application and login successfully, the HomeCtrl is supposed to make a get request to the server for data for the logged in user.
What I want is this data to be loaded as a list in the home.html. Here's my home.html
<h3 class="subHeader"> Rooms </h3>
<ul class="nav nav-sidebar">
<!-- <li class="active">Overview <span class="sr-only">(current)</span></li> -->
<li ng-repeat="room in roomNames"><a>{{room}}</a></li>
</ul>
However, on successful login, the roomNames variable is empty initially. As soon as I refresh the page, the html list gets populated.
How do I ensure the list is populated as soon as the home.html page opens?
try using the success and errorcallbacks from $http, it would be better to place this functionality into a factory
myApp.controller('HomeCtrl', ['$scope', '$http', '$location',
function($scope, $http, $location) {
console.log("Hello World from home controller");
var refresh = function() {
$http.get('/roomNames')
.then(function successCallback(response) {
$scope.roomNames = response;
}, function errorCallback(response) {
//output an error if failed?
});
}
refresh();
}
]);
This is because, you move on to home page before your server you access. Therefore, on the home page, you will not get the data, and get them after the refresh.
Do redirected to the page only after successful authentication.
myApp.controller('LoginCtrl', ['$scope', '$http','$location', function($scope, $http, $location) {
$scope.login = function() {
var data = JSON.stringify({user: $scope.user.id, password: $scope.user.password, type: "m.login.password"});
$http.post("http://localhost:8008/_matrix/client/api/v1/login", data).then(function mySuccess(details){
$http.post('/login',details.data).success(function(response){
console.log(response);
$location.path('home'); // Redirect after success login
})
.catch(function(data){
console.error("Error in login",data);
});
}, function myError(err) {
console.log(err);
alert("Invalid username/password")
});
};
}]);
Lets say i list all users in a list, when i click a user i want to route to a new view and get the data for the selected person.
What is the preferred way? Should i move the data i already got when i listed the users or should i create a new server call?
My first thought is to pass the data, but the problem with this is that the data the gets lost if the user refreshes the page.
What is the best practice to solve this?
Small example:
(function() {
var app = angular.module('app');
var controllerId = 'app.controllers.views.userList';
app.controller(controllerId, [
'$scope', 'UserService',function ($scope, userService) {
var vm = this;
vm.users = [];
userService.getAllUsers().success(function (data) {
vm.users= data.users;
});
var gotoUser = function(user) {
// Pass the user to UserDetail view.
}
}
]);
})();
<div data-ng-repeat="user in vm.users" ng-click="vm.gotoUser(user)">
<span>{{customer.firstname}} {{customer.lastname}}</span>
</div>
i now list the user details in UserDetail view, this view is now vulnerable against a browser refresh.
Typically most people just create a new server call, but I'll assume you're worried about performance. In this case you could create a service that provides the data and caches it in local storage.
On controller load, the controller can fetch the data from the service given the route params and then load the content. This will achieve both the effect of working on page refresh, and not needing an extra network request
Here's a simple example from one of my apps, error handling left out for simplicity, so use with caution
angular.
module('alienstreamApp')
.service('api', ['$http', '$q','$window', function($http, $q, $window) {
//meta data request functions
this.trending = function() {
}
this.request = function(url,params) {
var differed = $q.defer();
var storage = $window.localStorage;
var value = JSON.parse(storage.getItem(url+params))
if(value) {
differed.resolve(value);
} else {
$http.get("http://api.alienstream.com/"+url+"/?"+params)
.success(function(result){
differed.resolve(result);
storage.setItem(url+params,JSON.stringify(result))
})
}
return differed.promise;
}
}]);
I would say that you should start off simple and do a new server call when you hit the new route. My experience is that this simplifies development and you can put your effort on optimizing performance (or user experience...) where you will need it the most.
Something like this:
angular.module('app', ['ngRoute', 'ngResource'])
.factory('Users', function ($resource) {
return $resource('/api/Users/:userid', { userid: '#id' }, {
query: { method: 'GET', params: { userid: '' }, isArray: true }
});
});
.controller("UsersController",
['$scope', 'Users',
function ($scope, Users) {
$scope.loading = true;
$scope.users = Users.query(function () {
$scope.loading = false;
});
}]);
.controller("UserController",
['$scope', '$routeParams', 'Users',
function ($scope, $routeParams, Users) {
$scope.loading = true;
$scope.user = Users.get({ userid: $routeParams.userid }, function () {
$scope.loading = false;
});
$scope.submit = function () {
$scope.user.$update(function () {
alert("Saved ok!");
});
}
}]);
.config(
['$routeProvider', '$locationProvider',
function ($routeProvider, $locationProvider) {
$routeProvider
.when('/users', {
templateUrl: '/users.html',
controller: 'UsersController'
})
.when('/users/:userid', {
templateUrl: '/user.html',
controller: 'UserController'
})
.otherwise({ redirectTo: '/users' });
}
]
);