Angular UI Router dynamic states on refresh goes to 404 - angularjs

I'm loading states dynamically based on the current user role. But when the page is refreshed it takes to the 404 page. Also in $stateChangeStart event fromState.name is blank.
Is there a way to go to the state before refresh button was clicked? Should I store the state before refresh is pressed and then use it?
.state('404', {
url: '/404',
templateUrl: '404.tmpl.html',
controller: function ($scope, $state, APP) {
$scope.app = APP;
$scope.goHome = function () {
$state.go('default.page');
};
}
})
$urlRouterProvider.otherwise('/404');
....
$rootScope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) {
//fromState.name = '' on refresh
});
Thanks in advance!

The below seems to work, not sure if this is the best approach. On before unload event save the state, then use it in $stateChangeStart.
.run(function ($rootScope, $window, $state, authService, $http, $timeout, localStorageService) {
$rootScope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) {
if (authService.isLoggedIn()) {
if (toState.name === "404" && fromState.name === '' && localStorageService.get("LAST_STATE") !== "404") {
authService.loadStates($stateProviderRef).then(function () {
$state.go(localStorageService.get("LAST_STATE"), localStorageService.get("LAST_STATE_PARAMS"));
});
}
}
});
window.onbeforeunload = function () {
localStorageService.set("LAST_STATE", $state.current.name);
localStorageService.set("LAST_STATE_PARAMS", $state.params);
return null;
}
})

Related

angularjs-uirouter $state.go Error as .go undefined

Here imgetting Error in $statechangStart Here im trying to checking my credentials in $statechageStart
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('Login',{
url:'/LoginService',
templateUrl: '/ApiClient/Home/LoginPage.html',
controller:'LoginController'
})
$urlRouterProvider.otherwise('/')
})
.run(function ($rootScope) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams, options, $scope, $state) {
debugger;
if (toState.module == "Private" && sessionStorage.getItem('employee')!=null) {}
else {
event.preventDefault();
$state.go('Login');
}
You need to inject $state to your .run , otherwise it is undefined
.run(function ($rootScope, $state)
EDIT
It's a bad practice to use $state.go in $stateChangeStart event. For your purposes, you'd better apply the state.go after setting a timeout
$timeout($state.go.bind(null, 'Login'), 3000);

How to handle stateChangeStart event at controller level in angularjs?

I am trying to redirect to home page when specific views are refreshed in browser. If I handle stateChangeStart event on rootScope level, it all works fine and navigates to home page.
var payApp = angular.module('pay', ['ui.router', 'pay.controllers', 'pay.services', 'exceptionOverride']);
payApp.run(['$templateCache', '$rootScope', '$state', '$stateParams', '$window', '$location', function ($templateCache, $rootScope, $state, $stateParams, $window, $location) {
$templateCache.put(baseUrl, angular.element('#ui-view').html());
// Allows to retrieve UI Router state information from inside templates
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.$on('$stateChangeSuccess', function (event, toState) {
// Sets the layout name, which can be used to display different layouts (header, footer etc.)
// based on which page the user is located
$rootScope.layout = toState.layout;
});
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams, options) {
//When payment or order page is refreshed, navigate to home
if (fromState.name == '' && (toState.name == 'payment' || toState.name == 'order')) {
$location.url('/');
}
});
var windowElement = angular.element($window);
windowElement.on('beforeunload', function (event) {
var path = $location.path();
if (path == '/payment' || path == '/order') {
event.preventDefault();
}
});
}]);
But I am trying to move this logic to a specific controller level so the stateChangeStart event will be fired only for specific views which are using this controller.
var payControllers = angular.module('pay.controllers', ['ui.bootstrap', 'ngIdle']);
payControllers.controller('payPaymentCtrl', ['$scope', '$state', '$window', '$location', 'payDataService', 'Idle', 'Keepalive', '$uibModal',
function ($scope, $state, $window, $location, service, Idle, Keepalive, $uibModal) {
var windowElement = angular.element($window);
windowElement.on('beforeunload', function (event) {
var path = $location.path();
if (path == '/payment' || path == '/paymentcreated') {
event.preventDefault();
}
});
$scope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams, options) {
//When payment or order page is refreshed, navigate to home
//Both payment and order share the same controller.
if (fromState.name == '' && (toState.name == 'payment' || toState.name == 'order')) {
$location.url('/');
}
});
$scope.paymentOption = service.GetpaymentOption();
if ($scope.paymentOption == null) {
//$state.go('home', {}, { reload: true });
//$location.path('/').replace();
$location.url('/');
}
}]);
The beforeunload event fires in the controller when a view is refreshed in browser but stateChangeStart does not fire.
Also, I tried to get rid of the stateChangeStart event from the controller level and handle to go to home page when some crucial data is missing. It gives me an error saying "Unable to load property of undefined". It appears to be trying to load some data that is bound to angular scope elements which usually appears upon some operation on home page. I need it to look like just the way when I open the home page for the first time when the application is run.
Thanks for any suggestions.

cannot forward to another page in change route event ui router

In my application I am trying to redirect the user to get redirected to login if he is not logged in and if he is than restrict him from visiting login page And I implemented the same like this before as well but now its not working I would like to know what I am doing wrong
app.run(function ($rootScope, $state, authService) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if (toState === 'home' && authService.isAuthenticated()) {
event.preventDefault();
$state.go(fromState);
}
if (toState !== 'home' && !authService.isAuthenticated()) {
event.preventDefault();
$state.go('home');
}
});
});
I have done same here as well but it was working I don't know why that was working and this is not working.
The link for the code that was working

Change query param in url using UI-router

Using ui-router how can I accomplish the following URL change? For example, when a user goes to "/page?hello=True" I want the url to change to "/page?status=hello".
$stateProvider.state('page', {
url: '/page/:id?status',
controller: 'MyCtrl as myCtrl',
templateProvider: function($templateCache) {
return $templateCache.get('templates/route.html');
}
});
You can use the stateChangeStart event in the app.run method to listen for state changes into that route, and change anything you want on the params. Something like this, might need to play with toState and toParams to get it right for you...
.run(['$state', '$rootScope', function($state, $rootScope) {
$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
if (toState.name === 'invitation') {
//change toParams to whatever you want
}
});
});

Go to the error state and keep the URL to the state generating the error

I'm using this to catch errors and redirect to an error page
module.run(function ($state, $rootScope, translateService) {
$rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {
$state.go("app.error");
});
});
But this moves to the error state and changes the URL. I want to go to the error page and keep the URL to the page with the error.
I've tried using the location option,$state.go("app.error", null, { location: false }), but it keeps the URL of the state I'm coming from and not the one with the error.
Can I somehow go to the error state and keep the URL or go to the error state and then change the URL back to the URL of toState?
I solved it by sending the error information to the error state and then set the url with $location.path there.
module.run(function ($state, $rootScope) {
$rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {
$state.get("app.error").$error = {
toState: toState,
toParams: toParams,
fromState: fromState,
fromParams: fromParams,
message: error.message,
stack: error.stack
};
$state.go("app.error");
});
});
module.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("app.error", {
url: "/error",
resolve: {
error: function () {
return this.self.$error;
}
},
templateUrl: "app/error.tpl.html",
controller: function ($state, $scope, $log, $location, error) {
if (error) {
$location.path($state.href(error.toState, error.toParams).replace(/^#/, ""));
$log.error(error.message, error.stack);
}
$scope.error = error;
}
});
});
I think this does the trick (I found this trick some time ago, it wasn't documented):
$rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {
event.preventDefault();
$state.go("app.error", {}, { location: false });
});
https://github.com/angular-ui/ui-router/wiki
look at the part about $stateChangeError
To add to the accepted answer, I did a small change that allowed me to retain the error url but attempt to go to the homepage (or whatever state you want) when the user tries to refresh:
controller: function ($state, $scope, $log, $location, error) {
if (error) {
$log.error(error.message, error.stack);
}else{
$state.go('app'); // or app.home or whatever
}
$scope.error = error;
}

Resources