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;
}
});
}
}
Related
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 }
];
I am using the same component for my router, on the first click the component affected, but on the next click the component still in the first state.
Here is the script for changing the route
<a [routerLink]="['react/1']">link 1</a>
<a [routerLink]="['react/2']">link 2</a>
Here is my router module
panel-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router'
import { PanelCoursesComponent } from 'src/app/components/panel-courses/panel-courses.component';
import { PanelHomeComponent } from 'src/app/components/panel-home/panel-home.component';
import { PanelIntroComponent } from 'src/app/components/panel-intro/panel-intro.component';
const routes: Routes = [
{ path: '', component: PanelHomeComponent },
{ path: 'react', component: PanelIntroComponent },
{ path: 'react/:no', component: PanelCoursesComponent } //the target
]
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class PanelRoutingModule { }
panel-course.component.ts
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router'
#Component({
selector: 'app-panel-courses',
templateUrl: './panel-courses.component.html',
styleUrls: ['./panel-courses.component.scss']
})
export class PanelCoursesComponent implements OnInit {
url!: any
constructor(private route: ActivatedRoute, private router: Router) {
console.log('route')
}
ngOnInit(): void {
this.url = this.router.url
console.log(this.route.snapshot.params) //the test script
}
}
On the PanelCourseComponent I try to console log the params, but that's only executed one time on the first click.
Am I missing something?
You can use this.route.params.subscribe method for this case
Here is the example
ngOnInit(): void {
this.route.params.subscribe(params => {
console.log(params) // It will be executed whenever you click the link
})
}
by default pathMatch is set to 'prefix'. so paths will be matched against your current location and the first one witch "matches" will render its component. to make your paths match only "exact" match add pathMatch: 'full' for your routes
const routes: Routes = [
{ path: '', component: PanelHomeComponent, pathMatch: 'full' },
{ path: 'react', component: PanelIntroComponent, pathMatch: 'full' },
{ path: 'react/:no', component: PanelCoursesComponent } //the target
]
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.
I have a component parent app-sidebar that can have two different child depends on variable:
<app-content-right *ngIf="!componentService.getEditor.inView"></app-content-right>
<!-- alternative editors -->
<app-labtech-home *ngIf="componentService.getComponentEditor && componentService.getEditor.inView"></app-labtech-home>
I need to inform user with a modal when leave app-labtech-home to ask him to leave or not the page without saving. I catch the event with
#HostListener('document:click', ['$event'])
clickout(event) {
if(this.eRef.nativeElement.contains(event.target)) {
console.log("clicked inside")
} else {
if(window.confirm("Are you sure?"))
alert('Your action here');
}
}
inside app-labtech-home component but it exit without the modal, i need to intercept the exit and do it only if user accept. How can I achieve that? Thanks
PS: the route doesn't change, it is a different component in the same page (really a different project)
My routing module:
export const routes: Routes = [
{ path: 'login', component: LoginComponent},
{ path: '', component: HomeComponent, canActivate: [AuthGuard],canDeactivate:[BackButtonDeactiveGuard]}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
I think you looking for this:
link
Try like this:
Create DeactivateGuardService
.service
import { Injectable } from '#angular/core';
import { CanDeactivate } from '#angular/router';
import { Observable } from 'rxjs/Observable';
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
#Injectable()
export class DeactivateGuardService implements CanDeactivate<CanComponentDeactivate>{
canDeactivate(component: CanComponentDeactivate) {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
Add canDeactivate property in each component route
routing.module
#NgModule({
imports: [
RouterModule.forRoot([
{
path: 'example',
canDeactivate: [DeactivateGuardService],
component: ExampleComponent
}
])
]
Call the service method when ever user tries to leave the page having form dirty
.component
export class ExampleComponent {
loading: boolean = false;
#ViewChild('exampleForm') exampleForm: NgForm;
canDeactivate(): Observable<boolean> | boolean {
if (this.exampleForm.dirty) {
alert('Discard Unsaved Changes?');
}
return true;
}
}
I have route configuration set up via #NgModule. And I have a service that identifies what parts of the application should be shown for the user depending on certain conditions. I need to call that service and setup the routes according to the returned value.
Problem: Route configuration is setup inside an annotation and I can't get how to call the service in such setup.
To be more specific here is the example configuration I want to enhance.
My current routing setup:
const appRoutes: Routes = [
{
path: '',
redirectTo: 'first-route',
pathMatch: 'full'
},
{
path: 'first-route',
component: FirstComponent,
pathMatch: 'full'
},
{
path: 'second-route',
component: SecondComponent,
pathMatch: 'full'
},
...
];
#NgModule({
imports: [RouterModule.forChild(appRoutes)],
exports: [RouterModule]
})
export class MyRoutingModule {
}
The service that should change the route setup:
#Injectable()
export class MyService {
getAccessibleRoutes(): Observable<string[]> {...}
}
Question: How can I make a service call and change the routes?
Note: I also looked on "Dynamically adding routes in Angular" and "How we can add new routes dynamically into RouterModule(#NgModule imports)" but I haven't found clear answer there.
If I correctly understood your problem, I think you probably can consider using route guards to reach you goal. I suggest you to use guards feature to specify the conditions of accessing your routes, instead of changing the list of routes.
Please check this link for more information about route guards:
https://codecraft.tv/courses/angular/routing/router-guards/
I hope this will help you.
import { Injectable } from '#angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { YourSecurityService } from './your-security.service';
#Injectable()
export class YourRouteGuardService implements CanActivate {
constructor(
private router: Router,
private yourSecurityService: YourSecurityService) {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
console.log(state.url); // HERE YOU CAN GET REQUESTED ROUTE
if (this.yourSecurityService.checkIfUserHaveAccess())
return true;
this.router.navigate(['your-route-to-redirect']);
return false;
}
}
Next you should apply your guard to your route:
const appRoutes: Routes = [
{
path: 'someroute',
component: RouteComponent,
canActivate: [YourRouteGuardService]
},
...
]