Router: Show component based on access with same route path - javascript

I have a home route which is used by both an admin and a user, is there a way where I can show UserComponent if you are logged in as a user, and show AdminComponent if you are logged in as an admin?
This is what I currently have:
const routes: Routes = [
{ path: 'login', component: LoginComponent },
{
path: 'home',
component: HomeComponent,
children: [
// Children routes mix of user/admin paths
]
}
]
What I was thinking is that maybe I could do something like this, however, I don't know how to access the service at this point in the script.
component: this.userService.isAdmin ? AdminComponent : UserComponent,

You can do it like this in HomeComponent:
HTML:
<admin-component *ngIf="isAdmin; else userHome;"></admin-component>
<ng-template #userHome>
<user-component></user-component>
</ng-template>
TS:
class HomeComponent {
public isAdmin: boolean;
constructor(userService: UserService) {
this.isAdmin = userService.isAdmin;
}
}

Related

Angular 9 use two different layouts in the same application

My application contains two different layouts. One layout is the application where we show the top navigation and a sidebar.
<app-nav></app-nav>
<div>
<app-sidebar></app-sidebar>
<router-outlet></router-outlet>
</div>
and the second layout is the login and signup pages where we don't have the navigation bar and sidebar.
The naive solution will be to add ngIf to both elements based on the current route. But I prefer avoiding it. The reason is that we have code inside these components that we don't want to load where we don't need to.
Is there any better solution to this issue?
Have the AppComponent contain an router-outlet as the template.
#Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class AppComponent {
constructor() {
}
}
Then include routes as:
const routes: Routes = [
{
path: '',
pathMatch: 'full',
component: AppComponent,
canActivate: [LanguageGuard]
},
{
path: ':lang',
component: LanguageComponent,
children: [
{
path: 'partner',
loadChildren: () => import('./partner/partner.module').then(m => m.PartnerModule)
},
...ClientRoutes,
...AuthRoutes
]
}
];
My project have different layouts for the partner and ClientRoutes/AuthRoutes
Partner:
const routes: Routes = [{
path: '',
component: PartnerLayoutComponent,
children: [
{
path: '',
component: HomeComponent
},
{
path: 'profile',
component: ProfileComponent
}
]
}];
This is the content of ClientRoutes/AuthRoutes:
export const ClientRoutes: Routes = [{
path: '',
component: ClientLayoutComponent,
children: [
{
path: '',
component: HomeComponent
},
{
path: 'sofa',
component: SofaComponent
}
]
}];
Then you change my PartnerModule as your login module and lazy load it.
But don't every user need to login? Maybe only put the signup process in that module.
If you're lazy-loading your modules, it's easy:
Add a second "layout" page with a <router-outlet>
In your routes, define your route like this:
const routes:Routes=[{path:'some-path', component: YourLayoutComponent, loadChildren: ()=> import('./lazy-loaded-module/lazy-loaded.module').then(m=>m.LazyLoadedModule) }];

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.

Is it possible to guard the entirety of an Angular app?

I have my application set up where many of my components are protected. However, the user is still able to access the main page "/". I was wondering if it would be possible to redirect the user to /login if they are not authenticated without making ALL of my components children of whatever component I have on "/". I'll include a modified version of what I have below:
const routes: Routes = [
{
path: "login",
component: LoginComponent
},
{
path: "test",
component: TestComponent
},
{
path: "protected",
canActivate: [AuthGuardService],
component: ProtectedComponent
},
{
path: "alsoprotected/:id",
component: AlsoProtectedComponent,
canActivate: [AuthGuardService],
children: [
{ path: "child1", component: ChildOneComponent},
{ path: "child2", component: ChildTwoComponent},
{ path: "child3", component: ChildThreeComponent },
{ path: "child4", component: ChildFourComponent },
{ path: "child5", component: ChildFiveComponent },
{ path: "child6", component: ChildSixComponent },
{ path: "child7", component: ChildSevenComponent }
]
},
{
path: "protectedsettings",
canActivate: [AuthGuardService],
component: SettingsComponent
}
];
Is there some way to add my GuardService to my app-root component?
You can create a componentless route in the same level as login and move everything other than login inside that route. Then add the guard to that route.
const routes: Routes = [
{
path: "login",
component: LoginComponent
},
{
path: "",
canActivate: [AuthGuardService],
children: [
{
path: "test",
component: TestComponent
},
{
path: "protected",
canActivate: [AuthGuardService],
component: ProtectedComponent
},
{
path: "alsoprotected/:id",
component: AlsoProtectedComponent,
canActivate: [AuthGuardService],
children: [
{path: "child1", component: ChildOneComponent},
{path: "child2", component: ChildTwoComponent},
{path: "child3", component: ChildThreeComponent},
{path: "child4", component: ChildFourComponent},
{path: "child5", component: ChildFiveComponent},
{path: "child6", component: ChildSixComponent},
{path: "child7", component: ChildSevenComponent}
]
},
{
path: "protectedsettings",
canActivate: [AuthGuardService],
component: SettingsComponent
}
]
}
];
check this link for more info
Inside your app root component in the constructor you could use the router to catch the instance NavigationStart from the router.
export class AppComponent {
constructor(private router: Router) {
router.events.subscribe( (event: Event) => {
if (event instanceof NavigationStart) {
//Check either LocalStorage or cookies for value
if(!localStorage.GetItem('hasLoaded')){
this.router.navigate['./login']
}
}
});
}
}
Another option is a CanDeactiveRoute in your routing file
import { Injectable } from '#angular/core';
import { CanDeactivate } from '#angular/router';
import { Observable } from 'rxjs';
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
#Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate) {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
Using this check alongside localStorage is a good start, you could use something like server side sessions and a HTTP Interceptor alongside this also.
Be advised the user can disable this and it's not meant to obscure or hide sensitive data. Do that on a server using secure transmission mechanisms, you've been warned.

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.

Angular 2 Role based navigation on same path

I've a small question regarding Angular 2 router using version 3.0.0-rc.1 I want to navigate to different home component based on user role such as AdminComponent or UserComponent. Can anyone please help in modifying below routes so that I can achieve the desired functionality?
{path: 'login', component: LoginComponent}, // <--- This redirects to '/' in case user is logged in
{
path: '',
component: HomeComponent,
canActivate: [AuthGuardService], // <--- Check if user is logged in, else redirect to login
children: [
{
path: '',
component: AdminComponent // <--- Want to navigate here if user role is 'admin'
},
{
path: '',
component: UserComponent // <--- Want to navigate here if user role is 'user'
}
]
}
AuthGuardService.ts
import {Injectable} from "#angular/core";
import {CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot} from "#angular/router";
import {AuthService} from "./auth.service";
#Injectable()
export class AuthGuardService implements CanActivate {
constructor(private authService: AuthService, private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.authService.isLoggedIn()) {
return true;
}
// Store the attempted URL for redirecting
this.authService.redirectUrl = state.url;
// Navigate to the login page with extras
this.router.navigate(['/login']);
return false;
}
}
AuthService.ts
import {Injectable} from "#angular/core";
#Injectable()
export class AuthService {
redirectUrl: string;
logout() {
localStorage.clear();
}
isLoggedIn() {
return localStorage.getItem('token') !== null;
}
isAdmin() {
return localStorage.getItem('role') === 'admin';
}
}
Thanks.
You can achieve it by below way.
{path: 'login', component: LoginComponent}, // <--- This redirects to '/' in case user is logged in
{
path: '',
component: HomeComponent,
canActivate: [AuthGuardService],
}
this is your home component html(home.component.html)
<app-admin *ngIf="user_role==='admin'"></app-admin>
<app-user *ngIf="user_role==='user'"></app-user>
make sure you are assigning user_role in your typescript file of home component
this is your admin component html(admin.component.html)
<div>
this is admin component
</div>
this is your user component html(user.component.html)
<div>
this is user component
</div>
Hope, This will help you.
The problem is that you can't have two routes with the same path. The easiest change you can make is to change the path to something like this:
{
path: 'admin',
component: AdminComponent
},
{
path: 'user',
component: UserComponent
}
This is probably the best option because since you want your components to be different based on the user role. You might also want other components to be different and you can do that easily by adding children to the admin or the user routes.
In your AuthGuard you still only return true, but you make two other guards for the admin and user routes. Which check if the user is or isn't the admin.
And you redirect to the correct route by checking the user role once he loges in and then in the component you do router.navigate(['/admin']) or router.navigate(['/user'])

Categories