I would like to provide a path that redirects to a given page based on query parameters. For example:
/redirect?page=hero&id=1
should redirect to:
/hero/1
Is there any way to do this in the route config? Something like:
{ path: 'redirect?page&id', redirectTo: ':page/:id' }
I can get the redirectTo to respect path parameters but not query parameters. Any ideas?
I would like to provide a path that redirects to a given page based on query parameters. For example:
/redirect?page=hero&id=1
should redirect to:
/hero/1
Is there any way to do this in the route config? Something like:
{ path: 'redirect?page&id', redirectTo: ':page/:id' }
I can get the redirectTo to respect path parameters but not query parameters. Any ideas?
Share Improve this question edited Sep 10, 2024 at 13:12 times29 3,3733 gold badges25 silver badges43 bronze badges asked Jan 12, 2018 at 20:28 callmepillscallmepills 7229 silver badges13 bronze badges 04 Answers
Reset to default 2You can try to use redirectTo: '/:page/:id'
and provide extracted from your URL page
and id
values using custom UrlMatcher()
:
...
const appRoutes: Routes = [
{
path: 'hero/:id',
ponent: TestComponent
},
{
matcher: redirectMatcher,
redirectTo: '/:page/:id'
}
];
...
/**
* custom url matcher for router config
*/
export function redirectMatcher(url: UrlSegment[]) {
if (url[0] && url[0].path.includes('redirect')) {
const path = url[0].path;
// sanity check
if (path.includes('page') && path.includes('id')) {
return {
consumed: url,
posParams: {
page: new UrlSegment(path.match(/page=([^&]*)/)[1], {}),
id: new UrlSegment(path.match(/id=([^&]*)/)[1], {})
}
}
}
}
return null;
}
STACKBLITZ: https://stackblitz./edit/angular-t3tsak?file=app%2Ftest.ponent.ts
There is another issue when using redirectTo: ...
, active link is not updated, actually isActive
flag is not set to true
, it is seen on my stackblitz when acrive redirection links are not colored in red
No, there is no way of doing it by a configuration. YOu see, Angular's router does not explicitly define query parameters - any url can have an arbitrary number of query params, and the paths '/page/id' and '/page/id?key=value' are treated as the same in Angular and do map to the same ponent. There are other, more cumbersome workarounds. One is to create a dummy ponent and redirect based on ActivatedRoute.queryParams
Observable from the ponent's ngOnInit
method. You can easily see why this is a bad idea.
Another way is to create a resolver, this way you maybe can dismiss the ponent declaration and just redirect from the resolver, again, based on the ActivatedRoute.queryParams
Observable, which seems cleaner.
But I do not really get why one would need such a route in a front end application, if you want someone to visit '/page/id', then just navigate them to the page, without any intermediary tricks.
Angular >= 18
With Angular 18 you can use a RedirectFunction
. A route config like this should do the trick:
{
path: 'redirect',
redirectTo: route => `/${route.queryParams.page}/${route.queryParams.id}`
}
Angular < 18
You can solve it with a CanActivateFn
:
import { CanActivateFn, ParamMap, Router } from '@angular/router';
import { inject } from '@angular/core';
import { from } from 'rxjs';
export const redirectTo =
(redirectToUrl: (params: ParamMap) => string): CanActivateFn =>
route =>
from(inject(Router).navigateByUrl(redirectToUrl(route.queryParamMap)));
Then your route config:
{
path: 'redirect',
canActivate: [redirectTo(params => `/${params.get('page')}/${params.get('id')}`)],
children: []
}
Additional bonus - a Jest test for the CanActivateFn
:
import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, CanActivateFn, convertToParamMap, ParamMap, Router, RouterStateSnapshot } from '@angular/router';
import { redirectTo } from './redirect-to';
const redirectToUrl = (params: ParamMap) => `/${params.get('page')}/${params.get('id')}`;
describe('redirectWhileKeepingQueryParams', () => {
const executeGuard: CanActivateFn = (...guardParameters) =>
TestBed.runInInjectionContext(() => redirectTo(redirectToUrl)(...guardParameters));
beforeEach(() => {
TestBed.configureTestingModule({});
});
it('should be created', () => {
expect(executeGuard).toBeTruthy();
});
it('should redirect to the given route', () => {
// Arrange
const navigateByUrlSpy = jest.spyOn(TestBed.inject(Router), 'navigateByUrl');
const page = 'hero';
const id = 1;
const route = { queryParamMap: convertToParamMap({ page, id }) } as Partial<ActivatedRouteSnapshot> as ActivatedRouteSnapshot;
const state = {} as RouterStateSnapshot;
// Act
executeGuard(route, state);
// Assert
expect(navigateByUrlSpy).toHaveBeenCalledWith(`/${page}/${id}`);
});
});
this.router.navigate(['/inform/page'], { queryParams: { munity: 970 } });
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742371189a4431298.html
评论列表(0条)