'Different routes same component
I want to achieve something like this /products
shows all the products and /products/:category
shows all the products related to a specific category. To achieve that I have the following routes:
const productsRoutes: Routes = [
{
path: 'products',
component: ProductsComponent,
children: [
{
path: '',
component: ProductsListComponent,
},
{
path: ':category',
component: ProductsListComponent
}
]
}
];
Problem
When I switch between categories, everything is fine, when I switch between all products and category products, and vice-versa, Angular redraws the components and there's a flickering.
Angular 2 Router final version doesn't have Regex,as for as I know. Is there something that I'm missing, or for now this is the only solution?
Solution 1:[1]
you can solve it by adding routes
const routes: Routes = [
{ path: 'experience',
children: [
{ path: 'pending', component: ExperienceComponent },
{ path: 'requests', component: ExperienceComponent },
] }]
and in ExperienceComponent import
import { ActivatedRoute } from "@angular/router";
and in constructor add this parameter
constructor(public route: ActivatedRoute)
and inside constructor get url
this.route.url.subscribe(params => {
console.log(params[0].path);
})
Solution 2:[2]
I don't know if there is another way to do this but I managed to make it work using the following hack.
export const productsRoutes: Route[] = [
{
path: 'products',
component: ProductsComponent,
children: [
{
path: '',
pathMatch: 'prefix',
component: ProductsListComponent,
children: [
{
path: '',
component: EmptyComponent,
},
{
path: ':category',
component: EmptyComponent,
},
],
},
],
},
];
EmptyComponent:
import { Component } from '@angular/core';
@Component({
selector: 'GemainEmpty',
template: '<router-outlet></router-outlet>',
})
export class EmptyComponent {
}
Handle route changes on the ListComponent:
ngOnInit() {
this.routerEventsSubscription = this.router.events.subscribe((evt) => {
if (!(evt instanceof NavigationEnd)) {
return;
}
//Code to reload/filter list
}
}
And add a router outlet on the ListComponent template.
Solution 3:[3]
You could also define a redirect to a specific path:
{ path: '**', redirectTo: '/home', pathMatch: 'full' },
where /home
is the route you want to redirect to.
path: '**'
resolves all paths which are not defined
Solution 4:[4]
You can solve it by using redirect,
const productsRoutes: Routes = [
{
path: 'products',
component: ProductsComponent,
children: [
{
// path => '/products'
path: '',
redirectTo: ':category',
},
{
// path => '/products/:category'
path: ':category',
component: ProductsListComponent
}
]
}
];
It's more like set one path default, unless there is a matching path.
Solution 5:[5]
For problems like 'angular router optional parameter', 'angular route component reuse':
UrlMatcher is for creating a custom route matcher for a route pattern (which leads to your desired component). As a result, a customized route pattern is going to be handled, and the corresponding requests are handled by that component.
In the routes array,
{ matcher: productsMatcher, component: ProductsListComponent}
is a route, just as { path: 'somewhere', component: SomeComponent }
that defines a route.
A matcher takes the whole url string as an array of segments. The segments can be assigned to route params, which can be read by the component.
import { RouterModule, Routes, UrlMatchResult, UrlSegment } from '@angular/router';
const productsMatcher = (segments: UrlSegment[]): UrlMatchResult => {
if (segments.length === 1 && segments[0].path === 'products') {
return {
consumed: segments,
posParams: {}
}
}
if (segments.length === 2 && segments[0].path === 'products') {
return {
consumed: segments,
posParams: {
category: segments[1]
}
}
}
return <UrlMatchResult>(null as any);
}
const routes: Routes = [
// { path: '/products', component: ProductsListComponent },
// { path: '/products/:category', component: ProductsListComponent },
{ matcher: productsMatcher, component: ProductsListComponent},
];
In your component
ngOnInit(): void {
this.route.paramMap.subscribe(param => {
const category = param.get('category')
if (category) { this.loadStuff(category) }
})
}
All requests of the same url pattern are directed to this component.
As a result, (after it is created at the first request) there are no redraws/recreation of the ProductsListComponent. Thus there's no flickering when visiting /products/:category
route from /products
route: angular sees it as the same route, so the component won't reload.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Mohamed Abo Elmagd |
Solution 2 | Guilherme Meireles |
Solution 3 | Flosut Mözil |
Solution 4 | |
Solution 5 |