Conditional Page Display when application opens for the first time - angularjs

Hi I am just starting to learn angular && angular-ui-router and am trying to figure out how to determine when the app is opened for the first time to send the user to the login page or home page.
This is what i have so far:
codeArtApp.config(function($stateProvider, $urlRouterProvider){
$stateProvider
.state('login',{
url : '/login',
templateUrl:'App/scripts/login/loginView.html',
controller: 'loginCtrl'
})
.state('profile', {
url : '/profile',
templateUrl:'App/scripts/login/loginView.html',
controller: 'profileCtrl'
})
.state('404', {
url: '/404',
templateUrl:'App/scripts/views/404.html'
});
$urlRouterProvider.otherwise("404");
});
codeArtApp.run(['$state', '$rootScope', function($state, $rootScope, $log){
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState){
if(fromState.url === '^' && toState.url !== 'login'){
$state.go('login');
}
});
}]);
What I assumed here is that if fromState.url is set to ^ then the application is starting for the first time.
For some reason this code enters an infinite loop and I gt this stacktrace:
Now from what I can tell this happened because event if $state.go('login') gets execute toState.url is always 404.
I had hoped if $state.go('login') gets executed toState.url would have been set to login and that call would not be executed anymore.
I may not be setting this logic in the right place...
Can anyone tell me how conditionaly page displayed is achieved in Angular?

In your $urlRouterProvider.otherwise call you can pass a function instead of a string. Something like this:
$urlRouterProvider.otherwise(function($injector){
var $state = $injector.get('$state');
var Storage = $injector.get('Storage');
if (Storage.has('authToken')) {
$state.go('home');
}
else {
$state.go('login');
}
});
Hope this helps!

There is a link to working plunker, the main changes are shown in the code:
codeArtApp.run(['$state', '$rootScope',
function($state, $rootScope, $log) {
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState) {
// instead of
// toState.url !== 'login'
// we compare
// toState.name !== 'login'
var shouldLogin = fromState.url === '^'
&& toState.name !== 'login';
if(shouldLogin)
{
// this way we stop current execution
event.preventDefault();
// and navigate to login
$state.go('login');
}
});
}
]);
The toState.url would contain the url, i.e. '/login' instead of 'login'. Also check the : State Change Events to see more about the event.preventDefault(); . The plunker showing the above...

Related

angular event.preventDefault() on run methode

Am trying to route user to specific state when angular start, but it doesn't go to login when if it is true, instead of it goes to default routState
.run(function ($ionicPlatform, $rootScope, $state) {
var authToken = window.localStorage.getItem('authToken')
var shouldChangePassword=window.localStorage.getItem('shouldChangePassword')
if (authToken == 'undefined' || shouldChangePassword == 'true') {
event.preventDefault();
$state.go('login');
return;
}
.config(
//my routes
.state('login', {
url: '/login',
templateUrl: 'templates/account_login.html',
controller: 'loginCtrl',
})
$urlRouterProvider.otherwise('/tab/category');
)
how can i redirect to login and stop the app from going to default route
You could try hooking to UI-router's $stateChangeStart state change event:
.run(function ($ionicPlatform, $rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event) {
var authToken = window.localStorage.getItem('authToken');
var shouldChangePassword=window.localStorage.getItem('shouldChangePassword');
if (!authToken || shouldChangePassword) {
event.preventDefault();
$state.go('login');
}
});
But you might consider moving the authToken and shouldChangePassword to a separate service and read/set the value from/to that service instead of reading from the localstorage for every state change

AngularJS controller middleware

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

How can I avoid showing a page for a fraction of a second before angular ui-router redirects to another page?

I am using angular ui-router for routing and ng-token-auth for authentication on my website. If a signed in user tries to visit sign-in page, then he should be redirected to home page (code below).
$stateProvider
.state('sign-in',{
url: '/sign-in',
templateUrl: 'partials/registrations/sign-in.html',
controller: 'SigninCtrl as signin',
resolve: {
auth: function($auth, $state) {
$auth.validateUser().then(function(){
$state.go('home');
});
}
}
})
This works fine on state change or when I refresh the page. However, when I open the sign-in link on a new tab, it shows sign-in page for a fraction of a second and then redirects to home page.
How can I avoid showing sign-in page view before redirection?
$stateProvider
.state('sign-in',{
url: '/sign-in',
templateUrl: 'partials/registrations/sign-in.html',
controller: 'SigninCtrl as signin',
resolve: {
auth: function($auth, $state, $timeout) {
var promise = $auth.validateUser();
promise.then(function(){
$timeout(function() {
$state.go('home');
});
});
return promise;
}
}
})
You can use State Change Event - stateChangeStart .
$stateChangeStart - fired when the transition begins.
angular.module('MyApp').run(function($rootScope, $state) {
// Check authentication before changing state
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
// do authentication work here
});
});
For more help - https://github.com/angular-ui/ui-router/wiki

Angular states - resolve before exiting

My Angular app includes a main screen and several tabs and I'm using $stateProvider to switch between states. Whenever I'm leaving a tab (=state) I must perform an asynchronous operation. I would like to wait for that operation to complete before actually moving to the new tab. Somewhat like resolve that is done when leaving the state rather than entering.
How can this be achieved?
Example snippet:
$stateProvider
.state('myproject.main', {
url: '/main',
templateUrl: '...',
controller: 'MainCtrl'
})
.state('myproject.tabs.a', {
url: '/tab_a',
controller: 'TabACtrl',
templateUrl: '...',
onExit: doSave
})
.state('myproject.tabs.b', {
url: '/tab_b',
controller: 'TabBCtrl',
templateUrl: '...',
onExit: doSave
});
function doSave(MyService) {
return MyService.save(); //async, promise
}
Here I wanted to save (async) whenever switching between the tabs. However when entering the main state from a tab, I want to be sure that save has finished (doing the save on myproject.main's onEnter/resolve is not good for me).
Problem: when entering myproject.main (MainCtrl), the async MyService.save() operation is still processing. I want it to be completed/resolved.
I tried to hack it with the following piece of code, but it does not work - the state change enters a loop
.run(function($rootScope, $state, $stateParams, MyService){
$rootScope.$on('$stateChangeStart', function(ev, toState, toParams, fromState, fromParams){
if (toState.name === 'myproject.main' && //switching to main
fromState.name && //for a certain tab
fromParams.resume !== true ) {
ev.preventDefault(); //stop the state change
//do the save and then continue with the state change
MyService.save().then(function(){
$state.go(toState, {resume: true}) //continue with a "resume" parameter
});
}
});
});
Thanks!

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');
}
}
}

Resources