Can Angular router expose parent – current – next routes? - javascript

I have a module which initially redirects to
redirectTo: "/profile/bbb"
Where profile has two children :
{
path: '',
component: ProfileComponent,
children: [{
path: 'aaa',
component: AComponent
}, {
path: 'bbb',
component: BComponent
}]
}
Now - In profile's constructor I want to know what is the current route (which is profile) and what is the next route which it is goint to execute ( which is bbb).
This is the code :
profile.component.ts
constructor(private route: ActivatedRoute) {
route.children[0].url.subscribe(f => console.log(f))
}
But it shows me :
I guess I just queried the structure of the routes rather than the current active route
Question
How can I , in each path along the route , can know what is the parent route , current route , and where is it going to navigate ?
ps I don't want to do it via snapshot solution since component can be reused.
Online Demno

You can do this using ActivatedRoute.
Import it like:
import { ActivatedRoute } from '#angular/router';
Now inject it in the component:
constructor( private route: ActivatedRoute) {
console.log('Parent URL:', route.parent.url['value'][0].path);
console.log('Child URL:', route.firstChild.url['value'][0].path);
}
If you want to know complete URL for every navigation.
Then you can do this by using Router. Probably in AppComponent.
import { Router, NavigationStart, NavigationEnd } from '#angular/router';
A component will look like:
constructor(private router: Router) {
router.events.subscribe((route) => {
if (route instanceof NavigationStart) {
console.log("NavigationStart called:", route.url);
}
if (route instanceof NavigationEnd) {
console.log("NavigationEnd called:", route.url);
}
});
}

Related

In Angular 13 why does my route subscription stop it hits a route without a param?

I need a way to update a variable in my header component (always displayed) whenever a param changes in the URL.
My routing:
const routes: Routes = [
{
path: '',
component: DefaultLayoutComponent,
data: {
title: 'Home'
},
children: [
{
path: 'home',
component: HomeComponent
},
{
path: 'dashboard/:id',
component: DashboardComponent,
},
]
},
{path: '**', redirectTo: 'home'}
];
The dashboard component has an ID attached to it and this is what I need to track. In the event a user goes to a page without an ID (such as the home route) I want the ID to show as 0.
I have this working to where it will track the ID as long as they continue to hit routes with an ID but as soon as they navigate to home all tracking is stopped.
header.component
import { Component, Input } from '#angular/core';
import { ClassToggleService, HeaderComponent } from '#coreui/angular-pro';
import { ActivatedRoute } from '#angular/router';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-default-header',
templateUrl: './default-header.component.html',
})
export class DefaultHeaderComponent extends HeaderComponent {
private issuer: Subscription;
constructor(private classToggler: ClassToggleService,
private route: ActivatedRoute) {
super();
}
issuerID: number;
ngOnInit(): void {
this.route.children.forEach(child => {
child.params.subscribe(params => {
const id = params['id'] || 0
console.log('id ' + id)
this.issuerID = id
})
})
}
//To prevent memory leak
ngOnDestroy(): void {
if (this.issuer)
this.issuer.unsubscribe()
}
}

angular router how to call child component from the parent component

I have the following route-
const routes: Routes = [
{
path: '',
component: ParentComponent,
children: [
{
path: ':id',
component: ChildComponent,
},
]
}
];
in the constructor of the parent I want to navigate to some id, for example 'test'.
I tried this-
constructor(private router: Router) {
this.router.navigate(['child']);
}
and this-
constructor(private router: Router) {
this.router.navigate(['/child']);
}
and this-
constructor(private router: Router) {
this.router.navigate(['./child']);
}
and this-
constructor(private router: Router) {
this.router.navigate(['../child']);
}
my url is - http://localhost:4200/parent.
but all of this options I go to http://localhost:4200/child instead of http://localhost:4200/parent/child
Any idea why? how can I make it relative to the parent?
Because navigate takes in absolute paths.
You have to explicitly tell it to be relative :
constructor(
private router: Router,
private route: ActivatedRoute
) {
this.router.navigate(['child'], { relativeTo: this.route });
}

Angular: Setup routes depending on service method call

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]
},
...
]

Angular4: Reload data on refresh in app-wide singleton service

Working on a small angular project with a few components that represent the views, the app has a home component which contains a list of items which when clicked load the views in the other(appropriate) components. The project has a service that provides data to all the components, this service loads the shared data from an API when the home component's ngOnInit() {} method is called after which the data is available to every other component in the app.
Now, my problem is when a user enters the full url path to any other component apart from the home component(usually due to hitting refresh while on this component), the data in the service is lost and the component has nothing to display. Is there a way to make the home component always load first even when a direct path to the component is entered into the url? Should I just always check in every component if data has been loaded and load if not? Thank you
Here is the source for the Home Component.
import { Component, OnInit } from '#angular/core';
import { ServiceCodeService } from './service-code.service';
import { ActivatedRoute, Router } from '#angular/router';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
private specialityList: string[];
private route: ActivatedRoute;
private router: Router;
private svpList: string[];
constructor(private serviceCodeService: ServiceCodeService, route: ActivatedRoute, router: Router) {
this.route = route;
this.router = router;
}
ngOnInit() {
this.serviceCodeService.updateServiceCodesFromAPI().subscribe(
servCodes => {
this.specialityList = this.serviceCodeService.getAllSpecialities();
}
);
}
specialitySelected(item: any) {
this.router.navigate(['../speciality/'.concat(item)], {relativeTo: this.route});
}
svpSelected(item: any) {
this.router.navigate(['../svp/'.concat(item)], {relativeTo: this.route});
You could add a <router-outlet> to your home component, and then make the other views (/speciality etc...) children routes of the home route.
This would ensure that the home route always loads first
this.serviceCodeService.updateServiceCodesFromAPI().subscribe(
servCodes => {
if(servCodes) {
console.log(servCodes);
this.specialityList = this.serviceCodeService.getAllSpecialities();
}
}
);
You can do above mentioned code in all the components.

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