Is there a way to redirect a user to a specific state based on data from cookies when using ui-router?
I tried to do it from the .config() but since I'm not able to inject other dependencies it wasnt working.
I also tried to do it on the .run() block, but it just gives a loop (of course).
This is what I first tried on the .config()
function ConfigRouter($locationProvider, $stateProvider, $urlRouterProvider, Constant, localStorageService) {
$locationProvider.html5Mode(true);
$urlRouterProvider.when('/', function($injector) {
var $state = $injector.get('$state');
checkState($state);
});
$urlRouterProvider.when('', function($injector) {
var $state = $injector.get('$state');
checkState($state);
});
$urlRouterProvider.otherwise(function($injector) {
var $state = $injector.get('$state');
$state.go('error');
});
function checkState($state) {
var userCookie = localStorageService.cookie.get(Constant.cookieName);
if(userCookie.type == 1) {
$state.go('home-app');
} else if (userCookie.type == 2) {
$state.go('home-client');
} //and so on
}
}
Is there a way to do it? Or other way to achieve the same result? Basically I need to send the user to a different portion of the app based on the users role. If he is an admin, client, moderator, etc.. Each one has an specific app and need to retrieve specific data from server, this is why i want to do it, so i can request the data on the resolve of each state.
If you are using angular ui router, you can use resolve on the top state, there you can inject services which helps you to verify the cookie
you can also intercept and do it during
.run(["$rootScope", "$location", "$state", "services.userService", function ($rootScope, $location, $state) {
$rootScope.$on('$stateChangeStart', function (e, toState, toParams
, fromState, fromParams) {
// validation
});
more info https://github.com/angular-ui/ui-router/wiki#resolve
and examples here
angular ui-router login authentication
Defer Angular UI Router $stateChangeStart until server authorization response receieved
ej:
.state('main', {
templateUrl: 'app/modules/home/view.html',
abstract: true,
resolve: {
authorize: ['userService', "$state", "$q",
function (userService, $state, $q) {
return checkAuthorization(userService, $state, $q)
.then(function (user) {
return {user: user}
});
}]
},
controller: 'RootController'
})
// more states
var checkAuthorization = function(userService, $state){
//do all the necessary checks and return the user if he is already logged in
//redirecct to other page if the check failed
}
I did user check in the .run section:
.run(['$rootScope', '$state', '$cookies',
function ($rootScope, $state, $cookies) {
if ($cookies.get('token'))
$state.go('main');
else
$state.go('guest)
}]);
Of course than you should install 'token' in cookie. And now you don't need $urlRouterProvider in .config
Related
I am working on angularjs (1.6) and want to made a functionality in angular service, its call when a controller call and its service have an ajax code like
app.service('myServ', function($http, $window){
this.backdoor=function(){
$http({
method : 'get',
url : 'web_services/backdoor.php'
}).then(function(res){
// console.log(res.data);
// console.log(res.data.length);
if(res.data.length==0)
{
$window.location.href="index.html";
}
});
}});
and my controller code is :
app.controller('myCtrl', function($scope, $http, $window, myServ, $routeParams){
myServ.backdoor();
});
so the above code (service) is check a user session is created or not, but the problem is when session is not created on server side then my html page load for a second then server will call $window.location.href so please help me about the right way to do this....
I believe you need a resolve in angular.config. Its job is to run some code before you are being redirected to your route/state (for ngRoute or ui.router).
To do that you would need to have:
app.service('myServ', function($http, $window){
this.backdoor=function(){
return $http({ // return the promise if you need to use the values in the controller
method : 'get',
url : 'web_services/backdoor.php'
}).then(function(res){
if(res.data.length==0){ $window.location.href="index.html"; }
else{ return res.data; } // return the values
});
}});
and main part:
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/your_page/:route_params', {
templateUrl: 'your_page_partial.html',
controller: 'myCtrl',
resolve: {
resolvedVal: function resMyService(myServ, $routeParams){ // setting an injectable instance `resolvedVal`
/* use $routeParams values as parameters? */
return myServ.backdoor(); // calling your service
}
}}
);
}]);
Then it's enough to just inject your resolve into the controller:
app.controller('myCtrl', function($scope, $http, $window, resolvedVal){ // note: resolvedVal injection
$scope.my_data = resolvedVal;
});
What I am trying to do is verify user authentication and respond accordingly. Either populate the $rootScope with session data or redirect to the login page. I want the session data to be accessible to other controllers and views.
The Session response from the server is a JSON object:
{"user_id":"17","name":"Administrator","user_email":"admin#example.com"}
My app.js looks like this:
var app = angular.module('app', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider, $locationProvider){
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'app/views/login.html'
})
.state('logout', {
url:'/logout',
templateUrl: 'app/views/login.html'
})
.state('dashboard', {
url:'/dashboard',
templateUrl:'app/views/dashboard.html',
role: 0
});
})
.run(function($rootScope, $location, Data){
$rootScope.$on('$StateChangeStart', function (event, toState, fromState) {
$rootScope.authenticated = false;
Data.get('session').then(function (results) { // Sends request to server the above mention JSON object is returned
if (results.user_id) {
$rootScope.authenticated = true;
$rootScope.user_id = results.user_id;
$rootScope.name = results.name;
$rootScope.user_email = results.user_email;
} else {
$location.path("/login");
}
});
});
Then in my controller:
app.controller('AuthCtrl', ['$scope','$rootScope', '$location', '$http', 'Data', function ($scope, $rootScope, $location, $http, Data) {
$scope.login = {};
$scope.doLogin = function (user) {
Data.post('login', { // Sends login information to server
user: user
}).then(function (results) {
if (results.status == "success") {
$location.path('dashboard');
}
});
};
$scope.logout = function () {
Data.get('logout').then(function (results) { // sends logout request to server
$location.path('login');
});
}
}]);
The login function and response works as it should. The logout function works and destroys the session. The API on the server responds the way it should, but the session data is not stored or accessible in the $rootScope and I can not use it in my views.
The dashboard view looks like this:
<div ng-controller="AuthCtrl">
<h4>User Authenticated</h4>
User ID: {{user_id}}
<br/>NAME: {{name}}
<br/>E-MAIL: {{user_email}}
<br/>
<a ng-click="logout();">Logout</a>
</div>
I'm not sure if I am using $rootScope.$on('$StateChangeStart', function(...) correctly. Any suggestions?
It should be $stateChangeStart. Note the first letter is small and not caps.
I have a question: When I'm in a page I want return to previous page. I use the $routeProvider. How can I read the previous url?
I try to use this code in my controller but doesn't work...
angular.module.controller('myController',
function($scope, $routeParams, $http, $location, $rootScope) {
$rootScope.$on("$routeChangeSuccess",
function (event, current, previous, rejection) {
console.log(previous);
$location.path('PREVIOUS PATH');
});
});
How can I read the previous path? Thanks!
I am not fully sure, what you want to achieve. So I would suggest, check this before you go your own way:
How to implement history.back() in angular.js
But, in case, you want to know how to keep the last state with angular and UI-Router, we can do it with a service. There is some naive implementation tracking just last state (not challenging the history.back())
Check the working example
Service definition:
.factory('PreviousState', ['$rootScope', '$state',
function ($rootScope, $state) {
var lastHref = "/home",
lastStateName = "home",
lastParams = {};
$rootScope.$on("$stateChangeSuccess", function (event, toState, toParams
, fromState, fromParams) {
lastStateName = fromState.name;
lastParams = fromParams;
lastHref = $state.href(lastStateName, lastParams)
})
return {
getLastHref: function (){ return lastHref ; },
goToLastState: function (){ return $state.go(lastStateName, lastParams); },
}
}])
So we just do listen the $stateChangeSuccess and keep the track of last state name and its $stateParams.
We can inject our service to all scopes:
.run(['$rootScope', 'PreviousState',
function ($rootScope, PreviousState) {
$rootScope.PreviousState = PreviousState;
}])
And we can use it as a click or href:
<button ng-click="PreviousState.goToLastState()">go back</button>
<a ng-href="#{{PreviousState.getLastHref()}}" > go to last href</a>
Check that in action here
To put it simple, I would like to check out that if the session is still alive (which means user has logged in) before displaying the view of some routes, if not, then redirect to log-in view.
I have tried to listen to $routeChangeStart event from inside the log-in page, which is displayed initially by default, but user can still go to other views by typing in the routes.
Now what I am doing is:
(function() {
'use strict';
angular.module("appClubS", ["appClubS.userModule", "appClubS.productModule", "clubsServices", "ngRoute", "ui.bootstrap"])
.config(routeConfigurator);
angular.module("appClubS")
.controller("checkLoginCtrl", checkLoginController);
checkLoginController.$inject = ['$scope', '$rootScope', '$location', 'userFactory'];
routeConfigurator.$inject = ['$routeProvider', '$locationProvider'];
function routeConfigurator($routeProvider, $locationProvider) {
$routeProvider.when("/home", {
templateUrl: "views/index.html"
});
// ...
$routeProvider.when("/account-profile/my-redeem", {
templateUrl: "views/member_zone/my.redeem.html",
controller: 'checkLoginCtrl'
});
$routeProvider.when("/account-profile/my-survey", {
templateUrl: "views/member_zone/my.survey.html",
controller: 'checkLoginCtrl'
});
}
function checkLoginController($scope, $rootScope, $location, userFactory) {
var loginStatus = userFactory.loggedin();
if (!loginStatus) {
alert('Please Login First!');
$location.path('/login');
}
}
})();
But the view still gets displayed before user is navigated to log-in page.
Could anyone help? Thanks so much in advance.
You can use a resolve function
$routeProvider.when("/home", {
templateUrl: "views/index.html",
resolve:{
checkLogin: function (sessionService) {
sessionService.redirectIfLogged();
}
}
});
So this ensures your check is runned before the view is rendered
I am trying to vary the page a user sees when they go to my website. If they are anonymous they should see the register page. If they have logged in they should see their dashboard.
I have a service which checks to see if the user is logged in (e.g. check cookies) which triggers when the Angular services load. I have tried to use the $routeProvider to redirect but the service has not been triggered when the $routeProvider is being initialized so it always thinks that the user is not logged in.
I can redirect easily once the initial page has been loaded but I am struggling to redirect the first page loaded. Can anyone give advice on how to do this?
Make sure to read comment under the answer. When I answered this question I didn't thought about unit tests and design. I was just demonstrating that what can be one of many ways to achieve the desired result
I think the best way to do it under controller or your app.config.run.
In your case you should create another module to check for user login status. Inject user login status checking module to your app module.
Here is the link to the sample followed by the app.js code
http://plnkr.co/edit/dCdCEgLjLeGf82o1MttS
var login = angular.module('myLoginCheck', [])
.factory('$logincheck', function () {
return function (userid) {
// Perform logical user logging. Check either
// by looking at cookies or make a call to server.
if (userid > 0) return true;
return false;
};
});
var app = angular.module('myApp', ['myLoginCheck']);
app.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/publicurl', {})
.when('/loginurl', {})
.when('/unauthorize', {})
.otherwise({redirectTo: '/'});
})
.run(function ($logincheck, $location) {
//console.log("Into run mode");
console.log("Userid 5 is logged in: ", $logincheck(5));
console.log("Userid 0 logged in: ", $logincheck(0));
//now redirect to appropriate path based on login status
if ($logincheck(0)) {
//$location.path('/loginurl'); or
}
else {
//$location.path('/publicurl'); or
}
});
app.controller('MainCtrl', function ($scope) {
$scope.name = 'World';
});
I just did this, by making a dummy template and small controller for the / path which redirects as appropriate.
controllers.controller('loginController',
['$scope', '$location', '$cookies',
function($scope, $location, $cookies) {
if (!!$cookies.user) {
console.log("already logged in!");
$location.path('/shows');
} else {
console.log("need to login!");
$location.path('/users');
}
}]);
var app = angular.module('app', ['ngRoute', 'ngCookies', 'controllers', 'services']);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.when('/users', {
templateUrl: "partial/users.html",
controller: 'userController'
});
$routeProvider.when('/shows', {
templateUrl: "partial/shows.html",
controller: 'showController'
});
$routeProvider.when('/', {
template: '',
controller: 'loginController'
});
$routeProvider.otherwise({
redirectTo: '/'
});
}]);