在 Angular 18 中,我尝试在导航之前解析一个值,但根据该值重定向到另一个页面。
请不要链接到 Davide Passafaro 标题为“Redirecting Guards and Resolvers in Angular v18”的页面。它没有回答我的问题。
场景如下:
这是我到目前为止所拥有的:
const routes: Route = [
path: ":key",
component: ArtComponent,
resolve: {
art: () => inject(ArtService).get(key) // This automatically binds to a corresponding @Input() property on the component
},
canActivate: [
() => {
const router = inject(Router);
*** somehow redirect to 404 page if art is null ***
return true;
}
]
];
我显然错过了一些东西。另一种方法是在 ArtComponent 的 ngOnInit() 函数中执行重定向,但这听起来很恶心。
守卫先运行,然后解析器运行。
因此我们通过返回 observable 来获取守卫中的数据,并使用
map
访问里面的数据并确定是否重定向。
canActivate: [
(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
console.log('guard');
const router = inject(Router);
const artService = inject(ArtService);
return artService.get(route.params['id']).pipe(
map((data: any) => {
route.data = { ...route.data, temporaryData: data };
if (!data) {
return router.createUrlTree(['/']);
}
return true;
})
);
},
我们还需要将此数据共享给解析器,这里我们添加一个属性
temporaryData
,其中包含来自API的数据,然后我们在解析中访问该数据以返回@Input
绑定。
resolve: {
art: (
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
) => {
console.log('resolve');
const temporaryData = route.data?.['temporaryData'];
// delete route.data?.['temporaryData'];
return temporaryData;
},
},
import { Component, Injectable, inject, Input } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import {
ActivatedRouteSnapshot,
provideRouter,
RouterModule,
RouterStateSnapshot,
Router,
withComponentInputBinding,
} from '@angular/router';
import { of, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { CommonModule } from '@angular/common';
@Injectable({
providedIn: 'root',
})
export class ArtService {
get(key: any): Observable<Object | null> {
return key === '1' ? of({ data: 1 }) : of(null);
}
}
@Component({
selector: 'app-child',
standalone: true,
imports: [CommonModule],
template: `
child: {{art | json}}
`,
})
export class Child {
name = 'Angular';
@Input() art: any;
}
@Component({
selector: 'app-root',
imports: [Child, RouterModule],
standalone: true,
template: `
<a routerLink="child/1">1</a> | <a routerLink="child/2">2</a>
<br/>
<router-outlet/>
`,
})
export class App {
name = 'Angular';
}
bootstrapApplication(App, {
providers: [
provideRouter(
[
{
path: 'child/:id',
component: Child,
resolve: {
art: (
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
) => {
console.log('resolve');
const temporaryData = route.data?.['temporaryData'];
// delete route.data?.['temporaryData'];
return temporaryData;
},
},
canActivate: [
(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
console.log('guard');
const router = inject(Router);
const artService = inject(ArtService);
return artService.get(route.params['id']).pipe(
map((data: any) => {
route.data = { ...route.data, temporaryData: data };
if (!data) {
return router.createUrlTree(['/']);
}
return true;
})
);
},
],
},
],
withComponentInputBinding()
),
],
});