i have the following code in my route provider:
project.config(['$routeProvider','$locationProvider',
function ($routeProvider,$locationProvider){
$routeProvider.
when('/start',{
templateUrl: 'start.html',
controller: 'startController'
}).
when('/event',{
templateUrl: 'event.html',
controller: 'eventController'
}).
when('/report',{
templateUrl: 'report.html',
controller: 'reportController'
}).
otherwise({
redirectTo: '/'
});
I have a rootscope variable admin with value of either 1 or 0
My current code sends the user to the start page if an unknown value is given to the route provider. I want the route provider to redirect the user to the event page if the user is an admin or to the start page if the user isnt an admin when an unknown value is given to the route provider.
I was thinking something like this might work, but it didnt.
otherwise({
redirectTo: defaultRedirect
});
$rootScope.admin == 1 ? $rootScope.defaultRedirect = "/event" : $rootScope.defaultRedirect = "/start"
It throws me an error.
Help is appreciated. Thanks.
No it will not work like that. Instead what you can do is have resolve in otherwise block, where you can check if loggedin user is admin or not (by checking $rootScope variable or calling authentication service). If service resolves user being admin then you can use $location service to change route using $location.path("/event") or $location.path("/start"). The code look like:
$routeProvider.otherwise({
resolve: {
load: [
'$rootScope', '$q', 'authentication', '$location', function ($rootScope, $q, authentication, $location) {
var defer = $q.defer();
function chooseRoute() {
if (authentication.identity === undefined) {
$location.path('/logon');
} else {
$location.path('/somewhere');
}
defer.reject();
}
if (authentication.identityResolved)
chooseRoute();
else {
var unbind = $rootScope.$watch(function () {
return authentication.identityResolved;
}, function (resolved) {
if (!resolved)
return;
chooseRoute();
unbind();
});
}
return defer.promise;
}
]
}
});
Another way is, you can check event $routeChangeStart in config/run block & then accordingly checking if user is admin you can redirect user to specific routes using $location service.
Related
I need to restrict the user from redirect and need to login only with authentication.
I tried but I can redirect to login page using back button and again come to same page using forward button. Even I can go to the required page using URL without login.
My code :
config.$inject = ['$routeProvider', '$locationProvider'];
function config($routeProvider, $locationProvider ) {
$routeProvider
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
controllerAs: 'vm'
})
.when('/profileData', {
controller: 'profileDataController',
templateUrl: 'view/profiledata.view.html',
controllerAs :'vm'
})
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm'
})
.when('/dashboard', {
// controller: 'PersonalInfoController',
templateUrl: 'view/dashboard.view.html',
controllerAs:'vm'
})
.otherwise({ redirectTo: '/login' });
}
run.$inject = ['$rootScope', '$location', '$cookieStore', '$http'];
function run($rootScope, $location, $cookieStore, $http) {
// keep user logged in after page refresh
$rootScope.globals = $cookieStore.get('globals') || {};
if ($rootScope.globals.currentUser) {
$http.defaults.headers.common['Authorization'] = 'Basic ' + $rootScope.globals.currentUser.authdata; // jshint ignore:line
}
$rootScope.$on('$locationChangeStart', function (event, next, current) {
//redirect to login page if not logged in and trying to access a restricted page
var restrictedPage = $.inArray($location.path(), ['/dashboard','/questionBank', '/profileData']) === -1;
/* var a = $location.$$absUrl.split('#')[1];
var patt = new RegExp(a);
var res = patt.test(restrictedPage); */
var loggedIn = $rootScope.globals.currentUser;
if (restrictedPage && !loggedIn) {
$location.path('/login');
}
});
}
use this :based on response from server
.when('/login', {
controller: 'LoginController',
templateUrl: 'view/login.view.html',
resolve:{
logincheck: checklogedin
})
/ resolve function for user....
var checklogedin = function($q ,$http,$location)
{
var deferred =$q.defer();
$http.get('/loggedin').success(function(user){
if (user.staus==true)
{
//goo
deferred.resolve();
}
else
{
deferred.reject();
$location.url('/login');
}
});
return deferred.promise
};
Based on the code that you have provided, I can't tell 100% what is going on in your code. But... you could always try to use the resolve property on each route that you don't want to allow access without authentication. Here is what that would look like for questionBank:
.when('/questionBank', {
controller: 'questionbankController',
templateUrl: 'view/questionbank.view.html',
controllerAs: 'vm',
resolve: {
auth: function(AuthService, $q){
if(AuthService.isAuthenticated()) return $q.resolve();
return $q.reject();
}
}
})
Each property of the resolve object should return a promise, and if that resolves... the route change works. If it rejects... the route change is not allowed. If the promise never resolves, you are screwed, so make sure it resolves or it will never do the route.
This isn't the only way to try what you are saying. It is A way of trying it.
You can also add event listener on your $scope and prevent moving in case of unauthenticated user.
$scope.$on('$locationChangeStart', function (event, next, current) {
if (!is_logged_in) {
event.preventDefault();
}
});
In my code I have two main controllers LoginCtrl and AppCtrl, and all other controllers are nested within AppCtrl. Then in AppCtrl I have this code, which will check for logged user.
if (localStorageService.get('authToken') === null) {
$state.go('login', {locale: CONFIG.defaultLang});
} else if (!userService.isLoggedIn()) {
tokenStorage.setAuthToken(localStorageService.get('authToken'));
userService.setIdentity(JSON.parse(localStorageService.get('user')));
}
As you can see I store auth token from server in local storage. When page loades this code will be executed and if you are not logged in you will be redirected. And because all other application controllers are nested within AppCtrl this code will be executed every time.
For more info about nested controllers try for example this article - https://rclayton.silvrback.com/parent-child-controller-communication
I am new to AngularJS. I made a simple app that have a login function using AngularJS. I used routing and on resolve i put some logic to check if user is logged in and then only proceed accordingly. I have everything working fine, the problem is, when i am not logged in, if i browse to /home it doesn't load the main.html page(that's how it's supposed to be) but a GET request gets called and that returns content of main.html in console.My code looks like this:
app.config(function($routeProvider){
$routeProvider.when('/', {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl',
resolve:{
test: function($http, $q,$location){
var defer = $q.defer();
//checks if user is logged and returns boolean
$http.post('login/getLoggedUser', {}, {}).success(function(data){
if(!data.logged){
defer.resolve(data);
$location.url('/');
}
else{
defer.resolve(data);
$location.url('/home')
}
});
return defer.promise;
}
}
})
.when('/home',{
templateUrl: 'partials/main.html',
controller: 'MainCtrl',
resolve:{
test: function($http, $q,$location){
var defer = $q.defer();
$http.post('login/getLoggedUser', {}, {}).success(function(data){
if(data.logged){
defer.resolve(data);
$location.url('/home');
}
else{
defer.resolve(data);
$location.url('/')
}
});
return defer.promise;
}
},
})
.otherwise({ redirectTo: '/' });
});
When i direct to /home, GET http:/localhost:8080/an-grails/partials/main.html is called in console which contains the content of main page. How do i disable this call? Is there any other method to do this? I read documentation on AngularJS official page and also watched few videos of Egghead.io about resolve and got idea that controller and template gets loaded only after resolve is processed, So what am i doing wrong?
The simplest way to manage rights in your different routes is to catch the $routeChangeStart which is fired by the $route service everytime the route is changed.
With this, you can access the actual route and the next one. This object is the same that you register with $routeProvider.when(). You just have to add a boolean and compare this boolean with the actual user status.
$rootScope.$on("$routeChangeStart", function(event, next, current) {
if (next.loggedOnly && !user.isLogged()) {
// You should implement a isLogged method to test if the user is logged
$location.replace();
// This prevent a redirect loop when going back in the browser
return $location.path("/");
}
}
And inside your route declaration use :
$routeProvider.when('/home', {
templateUrl: 'partials/main.html',
controller: 'MainCtrl',
loggedOnly: true
});
I need to build a User that can be the resut of different REST API call (each way comes from a specific route).
Let's say for this example that we can visit:
http://myapp/#user/:pseudo
http://myapp/#user/:user_id
angular.module('Test').config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/user/:pseudo', {
templateUrl: 'views/user.html',
controller: 'userFromPseudoCtrl'
}).
when('/user/:user_id', {
templateUrl: 'views/user.html',
controller: 'userFromIdCtrl'
}).
otherwise({
redirectTo: '/'
});
}
]);
then, i have 3 different controllers:
userFromPseudoCtrl
userFromIdCtrl
userCtrl (To control the view)
angular.module('Test').controller('userFromPseudoCtrl', function($User, $http) {
$http.get('/getUserFromPseudo/test')
.success(function(User) {
$User.set(User);
});
});
angular.module('Test').controller('userFromIdCtrl', function($User, $http) {
$http.get('/getUserFromId/test')
.success(function(User) {
$User.set(User);
});
});
angular.module('Test').controller('userCtrl', function($scope, $User) {
$scope.User = $User;
});
This way is not good because the userCtrl is called before the $http callback (from the router's controllers), so the User is actually empty into the page (i was hopping it will be automatically updated).
Before i try to manage with it (using $rootScope.$apply()), i am wondering what is the more optimize way to do this kind of process (loading datas from router's controller then display it).
Do you use as many controllers as i do ? Do you process these REST APIs calls in the same controller that "bind" your view ? I am interesting to know !
When you define your routes you can define an additional value named resolve which is an object where each field is a promise that when resolved will be injected into your controller:
Route Definition:
when('/user/:pseudo', {
templateUrl: 'views/user.html',
controller: 'userFromPseudoCtrl'
resolve: {dataNeeded: userPseudoService.getUserData()});
Service (new):
angular.module('Test').service('userPseudoService', function($http){
return $http.get('/getUserFromPseudo/test');
});
Controller:
angular.module('Test').controller('userFromPseudoCtrl', function(dataNeeded){});
The route will not change until the promise is resolved.
Is it possible to [execute a function] e.g. open a modal dialog window from the routeProvider when a certain route is requested?
myApp.config(function($routeProvider) {
$routeProvider
.when('/home',
{
controller: 'HomeCtrl',
templateUrl: 'Home/HomeView.html'
}
).when('/profile/:userId/changepwd',
function(){
$dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
alert('dialog closed with result: ' + result);
});
}
).otherwise({ redirectTo: '/home' });
});
PS: I want to cancel a route and instead open a dialog box. Opening the dialog box is not the only issue. Cancelling the route is the major issue.
You can pass your function as dependency in resolve and it will wait until dependency is resolved and when your dialog ends then change the route and modify history as you wish using $location
var app = angular.module('myApp', [])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
template: ' ',
controller: //empty function,
resolve: {
data1 : function($dialog, $location) {
var promise = $dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
alert('dialog closed with result: ' + result);
//Use [$location][1] to change the browser history
});
return promise;
}
}
});
}]);
Building on Rishabh's answer, and using sergey's location.skipReload from this Angular Issue you can use the following to create a dialog on route-change, defer the url-change indefinitely (in effect 'cancelling' the route change), and rewrite the URL bar back to '/' without causing another reload:
//Override normal $location with this version that allows location.skipReload().path(...)
// Be aware that url bar can now get out of sync with what's being displayed, so take care when using skipReload to avoid this.
// From https://github.com/angular/angular.js/issues/1699#issuecomment-22511464
app.factory('location', [
'$location',
'$route',
'$rootScope',
function ($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}
]);
app
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/home', {
controller: 'HomeCtrl',
templateUrl: 'Home/HomeView.html'
})
.when('/profile/:userId/changepwd', {
template: ' ',
controller: '',
resolve: {
data1: function($dialog, location, $q){
$dialog.messageBox(title, msg, btns)
.open()
.then(function(result){
//fires on modal close: rewrite url bar back to '/home'
location.skipReload().path('/home');
//Could also rewrite browser history here using location?
});
return $q.defer().promise; //Never resolves, so template ' ' and empty controller never actually get used.
}
}
})
.otherwise({
redirectTo: '/'
});
This feels like it leaks unresolved promises, and there may be a neater solution, but this worked for my purposes.
You can redirect the route to the same partial. You can do this by watching for a change in route using the following code. You can also show a dialog from here.
$rootScope.$on( '$routeChangeStart', function(event, next, current) {
if ( next.templateUrl == "xyz.html" ) {
//other validation logic, if it fails redirect user to the same page
$location.path( "/home" );
}
});
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: '/'
});
}]);