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
Related
I am trying to redrect user to login page if not auth my issue I cant see my code running if the user isnt auth,
userRoute.$inject = ['Router','$rootScope', '$state'];
function userRoute(Router,$rootScope,$state) {
$rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {
// We can catch the error thrown when the $requireSignIn promise is rejected
// and redirect the user back to the home page
debugger;
if (error === "AUTH_REQUIRED") {
$state.go("login");
}
});
and on my route I did:
controller: 'list.controler',
controllerAs: 'vm',
resolve: {
"firebaseUser": function (authService) {
// If the promise is rejected, it will throw a $stateChangeError
return authService.firebaseAuthObject.$requireSignIn();
}
}
});
Try:
$state.go("login"); //
.state("login", {
url:"/login",
controller: "loginCtrl",
templateUrl: "my/path/login.html"
})
Id advice you to use your moduleName.run() function in your js file whether is was app.js or another file name , it would be look like that :
//your moduleName and it's dependencies here
.run(["$rootScope", "$state", function($rootScope, $state) {
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
// We can catch the error thrown when the $requireSignIn promise is rejected
// and redirect the user back to the login page
if (error === "AUTH_REQUIRED") {
return $state.go("login");
}
});
}])
In your index.html
<script src=".../angular-ui-router.min.js"></script>
<script src=".../stateEvents.js"></script>
You'll need also to make a state for login, something like that :
.config(['$routeProvider', '$stateProvider', function($routeProvider, $stateProvider) {
$stateProvider.state('login', {
name: 'login',
url: '/login',
templateUrl: 'login/login.html',
controller: 'loginCtrl'
})
}])
I am using UI Router in my angular app. I am trying to integrate state change events, but they are not firing on state change. Everything else is working fine and there is no error in console. I came across following similar questions, but none of the solution worked for me:
$rootScope.$on("$routeChangeSuccess) or $rootScope.$on("$stateChangeSuccess) does not work when using ui-router(AngularJS)
angular + ui-router: $stateChangeSuccess triggered on state b but not on a.b
Following is my Angular code:
(function() {
angular.module("bootdemo", [
"ngResource",
"ui.router",
"bootdemo.core",
"bootdemo.index"
])
.run(function ($rootScope, $location, $state, $stateParams) {
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
alert("root change success");
})
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options){
alert("root change start");
})
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){
alert("root change error");
})
})
.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
$stateProvider
.state('index', {
url: "/",
templateUrl: '/index/templates/welcome.html',
controller: 'IndexController as vm'
})
.state('login', {
url: "/login",
templateUrl: '/index/templates/login.html',
controller: 'LoginController as ctrl'
})
.state('home', {
url: "/home",
templateUrl: '/index/templates/home.html',
controller: 'HomeController as ctrl'
})
});
}());
Left with no clue. I am not sure what I am missing.
StateChange events has been deprecated for ui.router >= 1.0
for the new ui.router use the following
StateChangeSuccess
$transitions.onSuccess({}, function() {
console.log("statechange success");
});
StateChangeStart
$transitions.onStart({}, function(trans) {
console.log("statechange start");
});
Check this migration guide for more information
If you are using the new ui-router (v1.0.0), the $stateChange* events will not work. You must use $transitions.on* hooks from now on.
You can read here.
https://ui-router.github.io/docs/latest/modules/ng1_state_events.html
https://github.com/angular-ui/ui-router/issues/2720
$state events are deprecated for angular version > 1.0.0.
now onward for change event we have to use $transitions
refer $transitions from here
I'm doing some onStateChange authorization like this:
angular
.module('app')
.run(['$rootScope', '$state', 'Auth', function ($rootScope, $state, Auth) {
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
console.log(toState);
if (!Auth.authorize(toState.data.allow)) {
console.log("Not authorized");
$state.go('app.auth.login', { redirect: toState.name });
}
console.log('Authorized');
});
}]);
Now, when I go to an unauthorized route, it acts as it should, up to a point. The authorization fails and it tries to redirect to app.auth.login. This is shown in the console.logs:
Object {url: "/", templateUrl: "modules/live/index.html", name: "app.live.index", data: Object}
app.routes.js:225 Not authorized
app.routes.js:222 Object {url: "/auth/login?redirect", templateUrl: "modules/auth/login.html", controller: "LoginController", name: "app.auth.login", data: Object}controller: "LoginController"data: Objectname: "app.auth.login"templateUrl: "modules/auth/login.html"url: "/auth/login?redirect"__proto__: Object
app.routes.js:229 Authorized
app.routes.js:229 Authorized
But the URL stays at the original state (the first attempted state), and I don't see the login screen. The LoginController never gets called (there's a console.log at the start that doesn't show.
If I visit /auth/login I see the login screen as intended.
Here's my app.routes.js:
/*****
* Auth
******/
.state('app.auth', {
abstract: true,
url: '',
template: '<div ui-view></div>',
data: {
allow: access.everyone
}
})
.state('app.auth.login', {
url: '/auth/login?redirect',
templateUrl: 'modules/auth/login.html',
controller: 'LoginController'
})
.state('app.auth.logout', {
url: '/auth/logout',
controller: 'LogoutController'
})
/*****
* Live
******/
.state('app.live', {
abstract: true,
url: '/live',
data: {
allow: access.live
}
})
.state('app.live.index', {
url: '/',
templateUrl: 'modules/live/index.html'
});
What can be causing this odd behaviour?
It happens in this cases, that we do forget to solve situation:
user is already (previously) redirected === user is going to $state.go('app.auth.login') ... no need to redirect
And we should not redirect in such case:
$rootScope.$on("$stateChangeStart",
function (event, toState, toParams, fromState, fromParams) {
if (toState.name === 'app.auth.login')
{
// get out of here, we are already redirected
return;
}
And once we do decide to redirect, we should stop current navigation with event.perventDefault();
if (!Auth.authorize(toState.data.allow)) {
// here
event.perventDefault();
$state.go('app.auth.login', { redirect: toState.name });
}
...
See more for example in this $stateChangeStart event continuing after state change or that Q & A with a working plunker
I would like to know if anyone has come up with a way to require state params when using ui router with angular.js and/or how to redirect if param is not specified. I would prefer not to have to put controller code in the stateProvider config, but am open to any suggestions.
I've come close with some things like:
if (typeof $stateParams.myId == 'undefined') {
...
}
But I cannot put that in a resolve, so I am not sure where or how to check that. I have an abstract state with children and the abstract state have the stateparam....
.state('mystate', {
abstract: true,
url: '/state/:permalink',
template: '<div ui-view></div>'
})
.state('mystate.config', {
url: '/config',
templateUrl: 'partials/conf/config.html'
})
TIA
OK...
Thanks to levi... I have this partially working:
.state('conference', {
abstract: true,
url: '/conference/:permalink',
data: {hasPerma: true},
module: 'conf',
template: '<div ui-view></div>',
})
.state('conference.config', {
url: '/config',
templateUrl: 'partials/conf/config.html'
})
... this is allowing me to check to toState data, but the fromState module (or data) do not show up for some reason:
.run(['$state', '$stateParams', '$rootScope', function($state, $stateParams, $rootScope) {
$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
console.log(toState.data.hasPerma); //working
console.log('from: ' + fromState.module); //not showing up
})
}])
So if I got to the base url and /conference/hello/config I can see the to info, but not the from ;-(
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