angular2 route guards validations - javascript

I'm creating a new app using angular and I want to set up some validations on route guards. For example my url is: localhost:4200/#/products and if I want to navigate from the menu to other page of my app localhost:4200/#/invoice I don't want that to be possible the navigation just manually modifying the url and typing invoice instead of products but only on menu click.
so this is my guard:
import { Injectable } from '#angular/core' ;
import { ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate, Router } from '#angular/router';
#Injectable()
export class AlwaysAuthGuard implements CanActivate {
canActivate() {
console.log('AlwaysAuthGuard');
return true;
}
}
and this is the routing service:
const appRoutes: Routes = [
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: 'login', component: AppLoginComponent, data: { title: 'Login' }},
{ path: 'invoice', component: InvoiceComponent, canActivate: [AlwaysAuthGuard], data: { title: 'Invoice' }},
{ path: 'products', component: ProductsComponent, data: { title: 'Products' }},
{ path: 'logout', component: LogoutComponent, data: { title: 'Logout' }},
{ path: '**', component: NotFoundComponent, data: { title: 'Page Not Found' }}
];
export const appRoutingProviders: any[] = [];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { useHash : true });
So how can I add some validations on which I restrict the url modification and allow user to navigate to other pages only from navigation menu when is pressing on click.

You can simply store some flag on menu click. example:
listen for click event on your menu link and then do the following:
localstorage.setItem('menu-clicked', 'true');
and then in your 'AlwaysAuthGuard' check if 'menu-clicked' is available in localstorage or not. example:
canActivate() {
// console.log('AlwaysAuthGuard');
if(localstorage.getItem('menu-clicked') == 'true'){
localstorage.removeItem('menu-clicked');
return true;
}
return false;
}

Related

Problems to redirect to auth route Angular

im starting to work with Angular, and im trying to create a simple route guard, to redirect user to login page, if my service return unauthorized.
To do that i created this route schema ->
const routes: Routes = [
{
path: '',
component: LoggedComponent,
children: [
{path: '', component: HomeComponent}
],
canActivate: [RouteGuard]
},
{
path: '',
component: AuthComponent,
children: [
{path: '', redirectTo: '/login', pathMatch: 'full'},
{path: 'login', component: LoginComponent},
{path: 'signin', component: SigninComponent}
]
},
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
And this is my guard service ->
PS: Im setting a default value false.
import {Subject, Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class RouteGuard implements CanActivate {
authorized: Subject<boolean> = new Subject();
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
this.setObservable(false)
return false;
}
getObservable(): Observable<boolean> {
console.log(`starts to observe`)
return this.authorized.asObservable();
}
setObservable(newState: boolean) {
console.log(`new observable state: ${newState}`)
this.authorized.next(newState)
}
}
Ok, since the value is returning false as default, I expect the route to be automatically redirected to the AuthComponent, because Auth is the second option at my routes[]. Right?
So...
At the AuthComponent i stated to observe the authorized status:
import {RouteGuard} from '#acn-collections-ws/shared';
#Component({
selector: 'acn-collections-ws-auth',
templateUrl: './auth.component.html',
styleUrls: ['./auth.component.scss']
})
export class AuthComponent implements OnInit {
constructor(private guard: RouteGuard, router: Router) {
console.log('im here');
this.guard.getObservable().subscribe(authorized => {
})
}
ngOnInit(): void {
}
}
But AuthComponent dosent load. it seems that when the canActivate parameter returns false, it does not go to the AuthComponent, it does not load anything. When the authorized (canActivate) returns true, it runs normally. Has anyone had a similar problem and can help me?
This is how I do it when authenticating using Firebase:
export class GuardGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router){}
async canActivate() {
const user = await this.authService.isLogged();
if(user){
return true;
}
else {
this.router.navigate(['login']);
return false;
}
}
}
If the user's logged return true so it loads the requested route if not redirects to the login route and return false.
And this is the routing:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { LoginComponent } from './modules/login/pages/login/login.component';
import { SignupComponent } from './modules/login/pages/signup/signup.component';
import { HeroComponent } from './shared/components/hero/hero.component';
import { NotFoundComponent } from './shared/components/not-found/not-found.component';
import { GuardGuard } from './shared/guards/guard.guard';
const routes: Routes = [
{ path: 'home', component: HeroComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'signup', component: SignupComponent },
{ path: 'login', component: LoginComponent },
{ path: 'tasks', loadChildren: ()=> import('./modules/task/task.module').then(m => m.TaskModule), canActivate: [GuardGuard] },
{ path: 'profile', loadChildren: ()=> import('./modules/user/user.module').then(m => m.UserModule), canActivate: [GuardGuard] },
{ path: '**', component: NotFoundComponent }
];

How to detect which parent layout component currently active in Angular in app.component?

How to check which layout component currently active in Angular in app.component ?
Here Is example my app-routing.module.ts.
{
path: '',
component: FrontComponent,
children: [
{
path: '',
redirectTo: 'login',
pathMatch: 'full'
},
{
path: 'login',
component: LoginComponent
}
]
},
{
path: '',
component: MainComponent,
canActivate: [AuthGuard],
children: [
{
path: 'dashboard',
component: DashboardComponent
},
{
path: 'message-list',
component: MessageListComponent,
}
]
}
Now I want to check layout component in app.component such as if it is 'FrontComponent' or 'MainComponent' . Because I want to perform some activity based on layout component. I have searched other questions but could not get required answer. can anyone please help me out? Thanks in advance.
Specifically looking to check layout frontcomponent is active in app.component.ts
You can learn it by looking at the URL with
import { Component } from '#angular/core';
import { Router } from '#angular/router';
#Component({
template: ''
})
export class Component {
constructor(private router: Router) {}
ngOnInit() {
if ( this.router.url.indexOf('login') != -1) {
console.log('Father is FrontComponent');
}
}
}
You can make a service where you store the current layout component name string, and this variable gets overridden when switching to the other component.

How to change router paths programmatically?

I'm building a Ionic app using Angular and calling an API to get some results. According to a particular property of the response object (such as "mode"="0" or mode="1" I need to change paths defined in app routing module, in particular to dynamically change the home page.
I'd like appcomponent (starting component) to call the API and to check the mode, then passing some routes according to that property.
E.g.:
I'd like to have something like:
if (mydata['mode']==="0") {
this.appRoutes = [
{
path: '',
redirectTo: 'firstPath',
pathMatch: 'full'
},
{
path: 'firstPath',
loadChildren: './firstpath.module#FistPathModule'
},
{
path: 'secondPath',
loadChildren: './secondpath.module#SecondPathModule'
}
]
} else if (my_data['mode']==="1") {
this.appRoutes = [
{
path: '',
redirectTo: 'secondPath',
pathMatch: 'full'
},
{
path: 'secondPath',
loadChildren: './secondpath.module#SecondPathModule'
},
]
}
Is there a way to do something like this inside the app-routing.module?
Hiding firstPath in the second case is possible as well?
This is not a correct way to make changes in app-routing file for such requirement.
You can use Guard to implement this.
In your child route file do like this:
{
path: '',
component: HomePage,
canActivate: [AuthGuard]
}
Auth Guard file:
import { Injectable } from '#angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, CanActivate } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
mode: number; **// You can save this mode variable into a common service and use it.**
constructor() { }
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
if(this.mode == 1) {
return false;
}else {
return true;
}
});
}
}

How to resolve page is missing in angular 2 boiler?

I just started learning angular 2 and cloned this repo:
https://github.com/AngularClass/angular-starter. Just adding an extra menu option called 'list'. I have created the component and added it to the routes:
export const ROUTES: Routes = [
{ path: '', component: HomeComponent },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'detail', loadChildren: './+detail#DetailModule'},
{ path: 'barrel', loadChildren: './+barrel#BarrelModule'},
{ path: '**', component: NoContentComponent },
{ path: 'list', component: ListComponent}
];
This is the list component:
import {
Component,
OnInit
} from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'list',
styles: [`
`],
template: `
<h1>list</h1>
<div>
For hot module reloading run
<pre>npm run start:hmr</pre>
</div>
<div>
<h3>
patrick#AngularClass.com
</h3>
</div>
<pre>this.localState = {{ localState | json }}</pre>
`
})
export class ListComponent implements OnInit {
public localState: any;
constructor(
public route: ActivatedRoute
) {}
public ngOnInit() {
this.route
.data
.subscribe((data: any) => {
/**
* Your resolved data from route.
*/
this.localState = data.yourData;
});
console.log('hello `List` component');
/**
* static data that is bundled
* var mockData = require('assets/mock-data/mock-data.json');
* console.log('mockData', mockData);
* if you're working with mock data you can also use http.get('assets/mock-data/mock-data.json')
*/
this.asyncDataWithWebpack();
}
private asyncDataWithWebpack() {
/**
* you can also async load mock data with 'es6-promise-loader'
* you would do this if you don't want the mock-data bundled
* remember that 'es6-promise-loader' is a promise
*/
setTimeout(() => {
System.import('../../assets/mock-data/mock-data.json')
.then((json) => {
console.log('async mockData', json);
this.localState = json;
});
});
}
}
For some reason I get this errormessage when I hit http://localhost:3000/#/list:
404 page missing
How can I solve this?
Move the list route to above the ** route like below:
export const ROUTES: Routes = [
{ path: '', component: HomeComponent },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'detail', loadChildren: './+detail#DetailModule'},
{ path: 'barrel', loadChildren: './+barrel#BarrelModule'},
{ path: 'list', component: ListComponent},
{ path: '**', component: NoContentComponent }
];
The router uses a first match wins strategy for matching routes. So, if the wildcard route ** is declared above 'list', the wild card route prevails.
Read the official router documentation here.
Just rearrange the order of routes in your app.routes.ts file and it should work.
export const ROUTES: Routes = [
{ path: '', component: HomeComponent },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'list', component: ListComponent},
{ path: 'detail', loadChildren: './+detail#DetailModule'},
{ path: 'barrel', loadChildren: './+barrel#BarrelModule'},
{ path: '**', component: NoContentComponent }
];

How to prevent state loading in angular 2

My component:
constructor(
private router: Router
) {
router.events.subscribe((val) => {
if (val instanceof NavigationStart && !isloggedIn) {
console.log(val);
}
});
}
If the user is logged in navigationStart, I want to prevent the user from loading the page if the user is not logged in. How to do this in angular 2?
You should create AuthGuard set it for all routes which user shouldn't land if not's login.
const routesConfig: Routes = [
{
path: 'admin',
component: AdminLayoutComponent,
canActivate: [AuthGuard],
children: [
{ path: 'dashboard', component: AdminDashboardComponent },
]
},
{path: 'admin-login', component: AdminLoginComponent},
{path: 'login', component: LoginComponent},
{path: '**', redirectTo: ''}
];
Here is simple AuthGuard.
#Injectable()
export class AuthGuard implements CanActivate {
constructor() {}
canActivate() {
let user = JSON.parse(localStorage.getItem('user'))
// here do logic for navigate to login if user don't have local storage...
return true;
}
}
For more information check this link.

Categories