I have the following routing configuration.
@RouteConfig([
{
path: '/home',
name: 'Homepage',
component: HomepageComponent,
useAsDefault: true
}
)
export class AppComponent {
}
whenever the browser is pointed to /home this route works but not for /Home or any other case variations. How can I make the router to route to the component without caring the case.
thanks
Here's what I did.
import { DefaultUrlSerializer, UrlTree } from '@angular/router';
export class LowerCaseUrlSerializer extends DefaultUrlSerializer {
parse(url: string): UrlTree {
// Optional Step: Do some stuff with the url if needed.
// If you lower it in the optional step
// you don't need to use "toLowerCase"
// when you pass it down to the next function
return super.parse(url.toLowerCase());
}
}
And
@NgModule({
imports: [
...
],
declarations: [AppComponent],
providers: [
{
provide: UrlSerializer,
useClass: LowerCaseUrlSerializer
}
],
bootstrap: [AppComponent]
})
update
This didn't make it into the new router yet
original
Regex matchers were introduced recently. This might help for your use case.
See https://github.com/angular/angular/pull/7332/files
And this Plunker from Brandon Roberts
@RouteConfig([
{ name : 'Test',
//path : '/test',
regex: '^(.+)/(.+)$',
serializer: (params) => new GeneratedUrl(`/${params.a}/${params.b}`, {c: params.c}),
component: Test
// useAsDefault: true
}
])
A little fix to Timothy's answer, which doesn't change the case of matched parameter names and values:
import {Route, UrlSegment, UrlSegmentGroup} from '@angular/router';
export function caseInsensitiveMatcher(url: string) {
return function(
segments: UrlSegment[],
segmentGroup: UrlSegmentGroup,
route: Route
) {
const matchSegments = url.split('/');
if (
matchSegments.length > segments.length ||
(matchSegments.length !== segments.length && route.pathMatch === 'full')
) {
return null;
}
const consumed: UrlSegment[] = [];
const posParams: {[name: string]: UrlSegment} = {};
for (let index = 0; index < matchSegments.length; ++index) {
const segment = segments[index].toString().toLowerCase();
const matchSegment = matchSegments[index];
if (matchSegment.startsWith(':')) {
posParams[matchSegment.slice(1)] = segments[index];
consumed.push(segments[index]);
} else if (segment.toLowerCase() === matchSegment.toLowerCase()) {
consumed.push(segments[index]);
} else {
return null;
}
}
return { consumed, posParams };
};
}
Edit: beside the problem explained above, there is another subtle bug which is resolved now. The for loop should iterate over matchSegments instead of segments.
I did this in my app.component.ts:
export class AppComponent implements OnInit {
constructor(private _route: Router) { }
public ngOnInit() {
this._route.events.subscribe(event => {
if (event instanceof NavigationStart) {
let url = (<NavigationStart>event).url;
if (url !== url.toLowerCase()) {
this._route.navigateByUrl((<NavigationStart>event).url.toLowerCase());
}
}
});
}
}
and this is needed on router-link to make it active when selected:
<a routerLink="/heroes" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: false }">Heroes</a>
Note: The following works in Angular 4.x
I just use a matcher function:
import { RouterModule, UrlSegment, UrlSegmentGroup, Route } from '@angular/router';
function CaseInsensitiveMatcher(url: string) {
url = url.toLowerCase();
return function(
segments: UrlSegment[],
segmentGroup: UrlSegmentGroup,
route: Route
) {
let matchSegments = url.split('/');
if (
matchSegments.length > segments.length ||
(matchSegments.length !== segments.length && route.pathMatch === 'full')
) {
return null;
}
let consumed: UrlSegment[] = [];
let posParams: {[name: string]: UrlSegment} = {};
for (let index = 0; index < segments.length; ++index) {
let segment = segments[index].toString().toLowerCase();
let matchSegment = matchSegments[index];
if (matchSegment.startsWith(':')) {
posParams[matchSegment.slice(1)] = segments[index];
consumed.push(segments[index]);
}
else if (segment === matchSegment) {
consumed.push(segments[index]);
}
else {
return null;
}
}
return { consumed, posParams };
}
}
With:
@NgModule({
imports: [
...
RouterModule.forRoot([
{ matcher: CaseInsensitiveMatcher('user/:id'), component: ProfileComponent },
])
],
declarations: [
...
],
bootstrap: [
AppComponent
]
})
Edit: I just found out that in order to work with AoT compilation, the @NgModule portion would look more like this:
export function profileMatch() {
return CaseInsensitiveMatcher('user/:id').apply(this, arguments);
}
@NgModule({
imports: [
...
RouterModule.forRoot([
{ matcher: profileMatch, component: ProfileComponent },
])
],
declarations: [
...
],
bootstrap: [
AppComponent
]
})
My workaround for this issue:
/* IMPORTS */
let routeEntries = [
{ path: '/home', component: HomePage }
/* DEFAULT ROUTE */
{ path: '/', component: HomePage },
/* NOT FOUND ROUTE */
{ path: '*', component: HomePage }
];
@Component(/* SETUP */)
@Routes(routeEntries)
export App implements OnInit {
/* STUFF */
ngOnInit() {
// subscribe to router changes
this.router.changes.forEach(() => {
let routerLink = location.pathname;
let routerLinkLower = routerLink.toLowerCase();
// if the route does not exist, check for the lowercase version
if (!routeEntries.find((route) => { return route.path === routerLink; })) {
this.router.navigate([routerLinkLower]);
}
// if the route is correct, set the active page
else {
// do something here if required
}
});
}
}
This works with the RC1 router and goes along well with route variations, eg:
'{domain}:{port}/HoMe'
'{domain}:{port}/homE'
'{domain}:{port}/Home'
...
This is how i fixed this issue
{ path: '/home', redirectTo: ['/Home'] },
{ path: '/Home', component: HomeComponent, name: 'Home' },
来源:https://stackoverflow.com/questions/36154672/angular2-make-route-paths-case-insensitive