Angular 18:如何重定向解析结果

问题描述 投票:0回答:1

在 Angular 18 中,我尝试在导航之前解析一个值,但根据该值重定向到另一个页面。

请不要链接到 Davide Passafaro 标题为“Redirecting Guards and Resolvers in Angular v18”的页面。它没有回答我的问题。

场景如下:

  1. 在名为 key 的 URL 中传递一个路径参数。
  2. 我使用该键从该键引用的后端获取一个值(描述一件艺术品)。
  3. 如果返回有效值,我希望将该值绑定到组件。
  4. 如果我收到空值,我想重定向到另一个显示 404 - 未找到消息的页面。

这是我到目前为止所拥有的:

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() 函数中执行重定向,但这听起来很恶心。

angular input angular-router resolver canactivate
1个回答
0
投票

守卫先运行,然后解析器运行。

因此我们通过返回 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()
    ),
  ],
});

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.