AngularJS controller middleware - angularjs

I have an Angular endpoint like so:
$stateProvider.state("auth.signin", {
url: "/signin",
views: {
"auth-view#auth": {
templateUrl: "views/auth/signin.html",
controller: "SigninController"
}
}
});
I want a before filter (or a middleware) for my SigninController so if the user is already logged in, I want to redirect him to my HomeController.
In pseudo code, I'm looking for something like this:
$stateProvider.state("auth.signin", {
url: "/signin",
views: {
"auth-view#auth": {
templateUrl: "views/auth/signin.html",
controller: "SigninController"
}
},
before: () => {
if (User.loggedIn() === true) {
return $state.go("app.home");
}
}
});
I used similar features on alot of frameworks so I'm pretty certain Angular has something like this too. What's the Angular way of doing it?
Thank you.
Ps: I'm not using Angular 2 yet.

The ui router triggers a $stateChangeStart event, which you can capture:
app.run(["$rootScope", "$state", function($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options) {
if (toState.name === "auth.signin" && userIsLoggedInLogicHere) {
event.preventDefault(); // prevent routing to the state
$state.transitionTo("app.home");
}
// else do nothing, it will just transition to the given state
})
}]);
See this documentation for reference

Related

Angularjs ui-router 404 not evaluating

The scenario is rather simple I have a local site that uses angular. I have my state provider set up us ui router lib.
If I type in http://localhost.com/#/lwejfpwef it will redirect me properly to my other wise clause to the state '/login'.
However I tried typing in http://localhost.com/lwjpoifwef it doesn't fire off any of the events that I have in my module config.
I have tried
$stateChangeSuccess
$stateChangeStart
$stateChangeError
$httpinterceptors
I'm not sure what I am doing wrong. It doesn't seem to hit any of the break points I put in there. Here is a snippet of what I have
angular.module('app').run(['$rootScope', '$state', 'service', function ($rootScope, $state, service) {
$rootScope.$on('$stateChangeSuccess', function (evt, to, params) {
alert('success');
});
$rootScope.$on('$stateChangeStart', function (event, to, params) {
alert('start');
});
$rootScope.$on('$stateChangeError', function (evt, toState, toParams, fromState, fromParams, error) {
$state.go('login');
});
}]);
angular.module('dealer-portal.core').config(CoreConfig);
function CoreConfig($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'wwwroot/app/login/login.html',
data: {
displayName: 'Login'
}
})
.state('home', {
url: '/home',
templateUrl: 'wwwroot/app/login/login.html',
data: {
displayName: 'Home'
}
})
.state('error', {
url: '/login'
});
$urlRouterProvider.otherwise('/login');
}
$state.go should have the state name and not the url passed in
$state.go('login');
and NOT
$state.go('/login');
Also, you need to inject $stateParams in your run function

Capturing and using URL in angular UI-router

I have a state:
.state('series', {
url: '/{series}/',
template: '<div configurator-list></div>',
resolve: {
stateService: 'ConfiguratorStateService'
},
params: {
series: '{series}'
},
controller: 'ConfiguratorListController',
ncyBreadcrumb: {
label: '{series}',
parent: 'home'
}
});
I'd like to use actual value for {series} that is in the URL to update a few things. I'm lost and haven't had any luck searching. Everything takes me to the UI-router page, but I don't see any concrete examples there.
You need to listen for any of the UI-Router state change events and use the parameters from that function to obtain it. Add a listener in upon your app run (substitute app name for 'myApp') which is detailed below...
(function() {
angular.module('myApp')
.run(runOptions);
runOptions.$inject = ['$rootScope', '$state'];
function runOptions($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if (toState.name === 'series') {
//output the parameter here... since the series parameter is actually the string of the url, use the url property
console.log(toState.url);
}
});
}
})();
There are other state change events you can use as well, depending on your intended use: https://github.com/angular-ui/ui-router/wiki#state-change-events
OR
What sounds more relevant with further reading of your question, modify your route definition...
Change url: '/{series}/' to '/:series'
Then, in your controller....
angular.controller('ConfiguratorListController', function($stateParams) {
var vm = this;
vm.series = $stateParams.series;
}

UI-Router: Is it possible to change a query parameter while the state is loading?

I am wondering if it is possible to change query parameter in the ui-router while a state is still being loaded.
I was thinking along the following lines but this does not work...
$stateProvider
.state('foo',{
url:'/foo?bar',
templateUrl:'app/foo.html',
controller: 'fooController as foo',
resolve: {
Resource: function($state) {
return somepromise()
.then(function(baz) {
if (baz !== some condition) {
$state.params.bar = 'newValue';
return;
}
});
}
}
Any Suggestion? Thanks...
You can handle it inside the state declaration (I prefer this way)
.state('foo', {
url: "/foo?bar", // not sure if this kind of url can be used
template: "",
controller: ['$state', function ($state, $stateParams) {
if ($stateParams.bar == 'something') {
$state.go('bar');
}
}]
})
Or you can redirect when the state is starting to change using event defined in ui-route
Normally I put these things in HomeController
$rootScope.$on('$stateChangeStart',
function (event, toState, toParams, fromState, fromParams) {
//console.log("state change:", fromState.name, fromParams, toState.name, toParams);
if (toState.name == 'foo' && toParams.bar == 'something') {
$state.go('bar');
}
});
Do beware this might trigger an infinite loop if not handled correctly.

Angularjs: restrict access to all pages except few

I'm using Angularjs with ui-router and JWT(which is a tool for token based authentication) and want to implement authentication.
Say i want to restrict access to all my pages except three: "/home", "/about" and "/login". How can I achieve this effect?
it's working ! enjoy :)
var scotchApp = angular.module('scotchApp', ['ngCookies','ngRoute','ui.bootstrap']);
scotchApp.run(['$rootScope', '$location', 'Auth', function($rootScope, $location, Auth) {
$rootScope.$on('$routeChangeStart', function(event, current) {
$rootScope.pageTitle = current.$$route.title;
if (!Auth.isLoggedIn() && current.$$route.withLogin || Auth.isLoggedIn() && current.$$route.withoutLogin) {
event.preventDefault();
$location.path('/');
}
});
}]);
scotchApp.config(function($routeProvider) {
$routeProvider
// route for the home page
.when('/list', {
templateUrl: 'pages/list.html',
controller: 'mainController',
title: 'User List',
withLogin: true,
})
.when('/register', {
templateUrl: 'pages/register.html',
controller: 'mainController',
title: 'Register',
withoutLogin: true,
});
});
bellow I'll explain for you how to protect access using angularjs Philosophy:
1- we supposed that you have factory named verifyLogin this factory used to verify if the user connect or not (inside this factory function named isAuth)
2 -file config contains the bellow code:
$stateProvider
.state('docApp.doc_components_profiles', {
needLogin: true,
url : '/admin/page1',
views: {
'content#docApp': {
templateUrl: 'app/admin/pages/profiles.html',
controller : 'AdminController as vm'
}
}
});
here you see that we write attribute named needLogin and we affect to this attribute value = true,in order to access to this path (admin pages) the user must be authenticated.
3 -now you can write as bellow to verify the path each time the user navigate from one to another
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams){
if(toState.needLogin){
if(verifyLogin.isAuth== false)
{
console.log("Ypou must connect before you access to this url!!");
$location.path('/login');
}
}
}

Using $state methods with $stateChangeStart toState and fromState in Angular ui-router

I'm writing a handler for $stateChangeStart:
var stateChangeStartHandler = function(e, toState, toParams, fromState, fromParams) {
if (toState.includes('internal') && !$cookies.MySession) {
e.preventDefault();
// Some login stuff.
}
};
$rootScope.$on('$stateChangeStart', stateChangeStartHandler);
toState does not have the includes method. Should I be doing something different, or is there a way to do what I'm trying to do?
Also, when //some login stuff includes a $state.go(...), I get an infinite loop. What might cause that?
Here's a more complete example demonstrating what we eventually got to work:
angular.module('test', ['ui.router', 'ngCookies'])
.config(['$stateProvider', '$cookiesProvider', function($stateProvider, $cookiesProvider) {
$stateProvider
.state('public', {
abstract: true
})
.state('public.login', {
url: '/login'
})
.state('tool', {
abstract: true
})
.state('tool.suggestions', {
url: '/suggestions'
});
}])
.run(['$state', '$cookies', '$rootScope', function($state, $cookies, $rootScope) {
$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
if (toState.name.indexOf('tool') > -1 && !$cookies.Session) {
// If logged out and transitioning to a logged in page:
e.preventDefault();
$state.go('public.login');
} else if (toState.name.indexOf('public') > -1 && $cookies.Session) {
// If logged in and transitioning to a logged out page:
e.preventDefault();
$state.go('tool.suggestions');
};
});
});
I don't like using indexOf to search for a particular state in the toState. It feels naive. I'm not sure why toState and fromState couldn't be an instance of the $state service, or why the $state service couldn't accept a state configuration override in its methods.
The infinite looping was caused by a mistake on our part. I don't love this, so I'm still looking for better answers.
Suggestion 1
When you add an object to $stateProvider.state that object is then passed with the state. So you can add additional properties which you can read later on when needed.
Example route configuration
$stateProvider
.state('public', {
abstract: true,
module: 'public'
})
.state('public.login', {
url: '/login',
module: 'public'
})
.state('tool', {
abstract: true,
module: 'private'
})
.state('tool.suggestions', {
url: '/suggestions',
module: 'private'
});
The $stateChangeStart event gives you acces to the toState and fromState objects. These state objects will contain the configuration properties.
Example check for the custom module property
$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
if (toState.module === 'private' && !$cookies.Session) {
// If logged out and transitioning to a logged in page:
e.preventDefault();
$state.go('public.login');
} else if (toState.module === 'public' && $cookies.Session) {
// If logged in and transitioning to a logged out page:
e.preventDefault();
$state.go('tool.suggestions');
};
});
I didn't change the logic of the cookies because I think that is out of scope for your question.
Suggestion 2
You can create a Helper to get you this to work more modular.
Value publicStates
myApp.value('publicStates', function(){
return {
module: 'public',
routes: [{
name: 'login',
config: {
url: '/login'
}
}]
};
});
Value privateStates
myApp.value('privateStates', function(){
return {
module: 'private',
routes: [{
name: 'suggestions',
config: {
url: '/suggestions'
}
}]
};
});
The Helper
myApp.provider('stateshelperConfig', function () {
this.config = {
// These are the properties we need to set
// $stateProvider: undefined
process: function (stateConfigs){
var module = stateConfigs.module;
$stateProvider = this.$stateProvider;
$stateProvider.state(module, {
abstract: true,
module: module
});
angular.forEach(stateConfigs, function (route){
route.config.module = module;
$stateProvider.state(module + route.name, route.config);
});
}
};
this.$get = function () {
return {
config: this.config
};
};
});
Now you can use the helper to add the state configuration to your state configuration.
myApp.config(['$stateProvider', '$urlRouterProvider',
'stateshelperConfigProvider', 'publicStates', 'privateStates',
function ($stateProvider, $urlRouterProvider, helper, publicStates, privateStates) {
helper.config.$stateProvider = $stateProvider;
helper.process(publicStates);
helper.process(privateStates);
}]);
This way you can abstract the repeated code, and come up with a more modular solution.
Note: the code above isn't tested

Resources