I am using the following code to resolve a resource when the main state is loaded. Is it possible to re - resolve the resource without reloading the page? I am avoiding reload so that the user experience is not affected.
$stateProvider
.state('main', {
url: '/',
templateUrl: 'publicApp/main.html',
controller: 'MainCtrl as mainCtrl',
resolve: {
userData: ["UserApi", function (UserApi) {
return UserApi.getUserData().$promise;
}]
}
})
.controller('MainCtrl', function (userData) {
console.log(userData.something);
})
Since is a public site, the user can visit any page without logging in but when the user logs in the page must customize based on the user data.
EDIT
I am using a modal for login so the state doesn't reload after logging in, I was thinking of throwing an event on $rootScope and then add listeners in controllers to load them again. But this doesn't look good, so I am looking for a better way
I currently have two options:
Reload page - will effect the user experience, so its the last option
Throw an event for the login modal and catch it in other controllers
Any better ideas?
Try using state reload once promise is resolved
$state.reload();
Related
A little back story.
I have public pages, not restricted
I have private pages, restricted that require login.
I am using Firebase Authentication for the login.
I have my $routeProvider set up in my .config() of my main .module() My restricted paths look like the following.
.when('/admin', {
controller: 'adminCtrl as admin',
templateUrl: 'pages/admin/dashboard.tpl.html',
resolve: {
"currentAuth": ["$firebaseAuth", function($firebaseAuth) {
//$requireAuth returns a promise if authenticated, rejects if not
var ref = new Firebase(fbUrl);
var authObj = $firebaseAuth(ref);
return authObj.$requireAuth();
}]
}
})
My question is about the resolve specifically, I am assuming it is working correctly because I am not seeing the templateUrl on my browser. (I know this for a fact, I removed the return and placed return true and my templateUrl appeared)
So right now, this promise in the resolve is getting rejected. Since I am not a logged in user.
My question is, how would I either a. send $routeProvider to my .otherwise route or b. place a redirect in the resolve if the promise is rejected.
Basically, If the user is not logged in, I want them sent back to the home page. Right now the browser is just showing a blank page.
After some more research (I realize now I needed to dig more, sorry won't happen again.)
I have found a solution by adding .run() to my application.
.run(function($rootScope, $location) {
$rootScope.$on("$routeChangeError", function(event, current, previous, eventObj) {
console.log(eventObj);
if (eventObj === 'AUTH_REQUIRED') {
$location.path("/");
}
});
})
This grabs my routeChangeError and redirects when I have the error of AUTH_REQUIRED.
Simple.
'use strict';
angular.module('cbApp')
.config(function ($stateProvider) {
$stateProvider
.state('search', {
url: '/college/search',
templateUrl: 'app/collegesearch/views/collegesearch.html',
controller: 'collegeSearchCtrl'
})
.state('searchCollegeFilter', {
url: '/college/search/:streamId?cities&courses&branches&ordering',
templateUrl: 'app/collegesearch/views/collegesearch.html',
controller: 'collegeSearchCtrl'
});
});
Here my application calls the 1st state i.e 'search' with a url /college/search. Inside the controller I transition to another state searchCollegeFilter.
What I wanna do is navigate the user back to the back they came from when they click the browser back button. Say they came from '/' I want them to go back to home page. But in browser back history there are 2 entries for college/search. I want this to happen only for the 1st time.
For this northing is do with angularjs, the thing is you need to watch browser back event before navigating "window.onhashchange". By observing that you can make you check and can redirect default page
What I am doing in a different application would serve the purpose:
Basically: Specify parent states!
-> Then the logic is becoming easy.
You don't have to be specific about history or back button or anything like that.
Basically:
-> Check in
$rootScope.$on("$onstateChange", ...
-> If
the fromState.parent equals toState.parent
then $window.history.replaceState({}, "My Detail State Page", $state.url(toState)
In my app I have a situation in which based on a certain condition, if a user access a certain route ('/checkinsuccess') before that controller and view loads a function gets run that checks if a certain flag is true using routeProviders resolve property. If this flag is true it redirects to a new route. Unfortunately it seems like the initial view and controller that I'm trying to redirect away from ('/checkinsuccess') are loading before the function being called in the resolve property finishes. This is causing issue since that initial view runs an auto logout function. Is there a way to run the check before the initial route loads, I thought that's what resolve did? Here's a piece of my code.
.when('/checkinsuccess', {
controller: 'thankuctrl',
templateUrl: 'views/MobileCheckin/checkin-success.html',
resolve: {
checkForWorkflowUpdates: function($location){
checkForWorkflowUpdates($location)
}
}
// check if workflow update has been made and load that route if true.
function checkForWorkflowUpdates($location){
var selectedForms = JSON.parse(sessionStorage.getItem('selectedForms'));
if (selectedForms) {
if(selectedForms.workersComp){
$location.path('/workerscomp');
} else if (selectedForms.motorVehical) {
$location.path('/autoaccident');
}
}
}
currently i'm developing a sample admin application using angularjs, in my application. i have used ui-router instead of ngRoute to define the urls. on my config function states are defined as below.
sampleModule.config(['$stateProvider','$urlRouterProvider',function ($stateProvider,$urlRouterProvider) {
$urlRouterProvider.otherwise('login');
$stateProvider
.state('login',{
url:'/login',
templateUrl: 'views/html/login.html',
controller: 'authCtrl'
}).state('main', {
url:'/main',
templateUrl: 'views/html/main.html',
controller: 'adminViewCtrl'
});
}]);
in the run state of the application i'm redirecting the users to their respective view as follows.
sampleModule.run(function ($rootScope, AuthService, $state) {
$rootScope.$on("$stateChangeStart", function (event) {
if (AuthService.isAuthenticated()) {
event.preventDefault();
$state.go('main');
} else {
event.preventDefault();
$state.go('login');
}
});
});
but the problem i'm facing is application giving following exception and crashes some times when URL changes.
RangeError: Maximum call stack size exceeded
I put a debug point to run function of the application and
and noticed that error coming because content inside if (AuthService.isAuthenticated()) { condition executing in a infinite loop.
below is the image for the errors in chrome developer tools
i'm confused about the things happening here, i Googled for few hours and was not able to come up with a straight answer, i even tried putting event.preventDefault() as some suggestions i saw , but it didn't helped to resolve the problem.
i'm wondering what error i'm doing here? is there any better way to restrict user access to the log-in page,or some other parts of the application after logging in to the application?
The problem here is that you are constantly redirecting user to same state. Here is what happens: user goes to some state, $stateChangeStart is triggered, you redirect user again to some other state, and again $stateChangeStart is triggered, you check authentication and redirect again, and that continues until RangeError appears. What you should probably do is only redirect user when he is unauthorized, if he is authorized, let him see the page he is looking for.
sampleModule.run(function ($rootScope, AuthService, $state) {
$rootScope.$on("$stateChangeStart", function (event, toState) {
if (!AuthService.isAuthenticated() && toState.name !== 'login') {
$state.go('login');
} else if(AuthService.isAuthenticated() && toState.name === 'login') {
$state.go('main');
}
});
});
Here you check if user is authorized and if navigation state is not login (since he already got redirected) and later check if it's login page he is wanting for and redirecting to main
Resolve is an interesting property to prevent a template to be displayed regarding some conditional logic dealing with a promise result (solved or rejected).
I use it in my application, here's a conceptual sample:
.config(['$routeProvider', 'securityAuthorizationProvider',
function ($routeProvider, securityAuthorizationProvider) {
$routeProvider.when('/test', {
templateUrl: '/myCorrespondingView.tpl.html',
controller: 'MyCorrespondingCtrl',
resolve: securityAuthorizationProvider.requireAuthenticatedUser
});
}])
So, this code expects to display /myCorrespondingView.tpl.html content if and only if securityAuthorizationProvider.requireAuthenticatedUser is resolved (promise term).
My expectation is: I don't want to change the URL to http://myApp.com/test if this promise in resolve part is rejected. The reason is simple, I don't want to uselessly reload the previous controller if my rejection logic is to let the user on his current page (thus needing a redirection to this latter) .
Is there an efficient way to achieve this with the resolve property other than shifting the conditional logic at the source, meaning into the previous controller?
I was dealing a similar problem some time ago. My solution was to redirect the user to a login page - you can use the page user is coming from - in the authentication provider (in your case it would be securityAuthorizationProvider.requireAuthenticatedUser) if the user wasn't logged in.
I know this is an old question, but for all users who are looking for an answer, i will provide my solution.
I have a popup / modal / alert whatever which is displayed over the whole page. in this popup is a history, so you can open a new view and can go back to the old view.
I added a feature that you can go back with your back-button on mouse or browser.
my js:
SYSTEM.run( [ "$rootScope", "Popup", function( $rootScope, Popup ) {
$rootScope.$on( "$routeChangeStart", function ( e ) {
if ( $rootScope.popup ) {
Popup.back();
e.preventDefault();
return;
}
} );
} );
So what you could do is, get the next route (provided in $routeChangeStart) and check if this url is secured and run your service. if your service is resolved redirect to the url and set the checking variable to true/false, so on the next change you won't check your service again.
Hope that helped.