Angular:如何根据 API 响应路由到不同的组件?
Angular: How to route to different components, depending on API response?
我想知道是否/如何在 Angular 10.
中实施特定的路由策略
为了解释,举这个简化的例子:
我有一个包含 4 个组件的 Angular 应用程序:
StudentListComponent
: 显示所有学生的列表
CourseListComponent
: 显示所有课程列表
StudentComponent
: 显示有关一名特定学生的详细信息
CourseComponent
: 显示一门特定课程的详细信息
我想实现如下路由策略
myapp.com/students
路由到“StudentListComponent”
myapp.com/courses
路由到“CourseListComponent”
myapp.com/millerh
路由到“StudentComponent”并显示用户名为“millerh”的学生的详细信息
myapp.com/math1
路由到“CourseComponent”并显示有关简称为“math1”的课程的详细信息
名称“millerh”和“math1”是唯一的,没有同时映射到学生和课程的 ID。 (编辑:也不会有名为“学生”或“课程”的学生或课程)
背景:链接会显示在另一个应用程序中,链接不能点击,不能copy/pasted,所以我希望路径越短越好。此外,高级用户更愿意直接输入 URL 而不是转到列表页面并搜索他们想要查看其详细信息的学生/课程。
为了实现这一点,我想在路由期间进行一个backend/API调用。 API 响应将表明,即“millerh”是学生、课程还是两者都不是。 取决于我想导航到相应的组件,并传递名称student/course 以及组件。我想避免重定向,即从 myapp.com/millerh 到 myapp.com/students/millerh,以避免同一资源有多个有效路径。
如何从开箱即用的 angular 路由模块开始?
非常感谢任何提示和建议!
我认为 Angular router 无法区分 millerh 是学生还是 math1 是课程,我认为你应该选择类似的东西:
myapp.com/students/millerh
myapp.com/courses/math1
编辑
假设您的一个用户想要搜索一个学生,他将输入 myapp.com/students/<studentName>
,然后该应用将导航至 students
组件,而 studentName
将是可用作路由参数,然后您可以使用 ngOnInit
生命周期挂钩对后端的学生端点进行 API 调用。
编辑编号 2
无需在 URL 中键入 students/courses 的解决方案,但在 URL 解决后您仍然可以使用它们
假设您一开始不想区分学生路线和课程路线。
想象你的用户类型 myapp.com/<someValue>
,现在你不知道他在找什么,学生还是课程,一开始他会登陆你的根组件,在这个组件中你可以使用 ngOnInit
来拨打 API 电话。
首先对您的学生端点进行 API 调用,如果有学生,请让您的应用程序以编程方式导航至 myapp.com/students/<someValue>
.
如果找不到学生,请 API 调用您的课程端点,如果有课程,请让您的应用以编程方式导航至 myapp.com/courses/<someValue>
.
最终会有对 url 课程学生的引用,但对您的用户来说会更容易,因为他们可以直接键入 myapp.com/<someValue>
.
无需在 URL 中键入 students/courses 的解决方案,你也不会将它们放在最后的 URL 中
您可以将它们放在一个页面中,而不是将您的学生组件和您的课程放在两个不同的页面中,在您的情况下可能是根组件,而不是重定向到 students
或 course
,您可以根据哪个 API 调用返回值来显示一个或另一个。
好的,我找到了一个我非常喜欢的工作解决方案:它似乎工作得很好,而且感觉不太hack。它并不完全符合任何已发布的建议 - 但感谢所有回复和评论,因为它们确实帮助我找到了最终解决方案!
最终的解决方案在其核心中使用了一个实现 CanActivate 的守卫,结合守卫内部的 router.resetConfig()
和 router.navigate()
。
作为我的解决方案的入口点,我使用标准路由模块。它对我的用例仍然有用,因为有些组件具有单个静态路由。
文件:app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './features/home/home.component';
import { StudentListComponent} from './features/student-list/student-list.component';
import { CourseListComponent} from './features/course-list/course-list.component';
import { LoadingComponent } from './features/loading/loading.component';
import { NotFoundComponent } from './features/not-found/not-found.component';
import { DynamicRouteGuard } from './guards/dynamic-route.guard';
const routes: Routes = [
{
path: '/',
component: HomeComponent
},
{
path: 'students',
component: StudentListComponent
},
{
path: 'courses',
component: CourseListComponent
},
{
path: 'not-found',
component: NotFoundComponent
},
{
path: '**',
canActivate: [ DynamicRouteGuard ],
component: LoadingComponent,
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
路径 /、students、courses 和 not-found 是大多数 Angular 应用程序中的普通静态路由。任何与这些不匹配的路由都将被底部的通配符路由处理。该路由加载一个组件,该组件可能包含一个加载微调器。当 Guard 异步地对后端进行 API 调用以确定加载哪个组件时,它将是可见的。
文件:动态-route.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { EntityTypeService } from '../../services/entity-type.service';
import { IEntityTypeModel } from '../../models/entity-type.model';
import { EntityType } from '../../models/entity-type.enum';
import { StudentDetailComponent } from '../features/student-detail/student-detail.component';
import { CourseDetailComponent } from '../features/course-detail/course-detail.component';
@Injectable({
providedIn: 'root'
})
export class DynamicRouteGuard implements CanActivate {
constructor(
private entityTypeService : EntityTypeService,
private router : Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
// At this point, only routes with a single path element are considered valid routes.
if (route.url.length != 1) {
this.router.navigate(['not-found']);
return false;
}
let path = route.url[0].toString();
// Ask backend, what kind of entity the requested path matches to
this.entityTypeService.getEntityTypeForPath(path).subscribe(response => {
let entityTypeModel = response as IEntityTypeModel;
// If backend did not recognize path --> redirect to page not found component.
if (entityTypeModel.entityType === EntityType.Unknown) {
this.router.navigate(['not-found']);
}
// Build a new routes array. Slicing is required as wildcard route
// should be omitted from the new routes array (risk of endless loop)
let routes = this.router.config;
let newRoutes = routes.slice(0, routes.length - 1);
// Add a new route for the requested path to the correct component.
switch(entityTypeModel.entityType) {
case EntityType.Student:
newRoutes.push({ path: path, component: StudentDetailComponent, data: { resourceName: path } });
break;
case EntityType.Course:
newRoutes.push({ path: path, component: CourseDetailComponent, data: { resourceName: path } });
break;
default:
this.router.navigate(['not-found']);
return;
}
// Reload routes and navigate.
this.router.resetConfig(newRoutes);
this.router.navigate([path]);
});
// Guard always returns true and loads LoadingComponent while API
// request is being executed.
return true;
}
}
在守卫中,可以访问请求的路由,并且可以轻松注入 API 服务。使用该服务,后端在数据库中查找路径,并且 returns 一个枚举值指示它是学生、课程还是两者都不是。根据这一点,一个新的路由被添加到 Routes 数组,对于那个特定的 student/course 名称,链接到匹配的组件。之后重新加载路由,路由器可以直接导航到正确的组件。
我想知道是否/如何在 Angular 10.
中实施特定的路由策略为了解释,举这个简化的例子:
我有一个包含 4 个组件的 Angular 应用程序:
StudentListComponent
: 显示所有学生的列表CourseListComponent
: 显示所有课程列表StudentComponent
: 显示有关一名特定学生的详细信息CourseComponent
: 显示一门特定课程的详细信息
我想实现如下路由策略
myapp.com/students
路由到“StudentListComponent”myapp.com/courses
路由到“CourseListComponent”myapp.com/millerh
路由到“StudentComponent”并显示用户名为“millerh”的学生的详细信息myapp.com/math1
路由到“CourseComponent”并显示有关简称为“math1”的课程的详细信息
名称“millerh”和“math1”是唯一的,没有同时映射到学生和课程的 ID。 (编辑:也不会有名为“学生”或“课程”的学生或课程)
背景:链接会显示在另一个应用程序中,链接不能点击,不能copy/pasted,所以我希望路径越短越好。此外,高级用户更愿意直接输入 URL 而不是转到列表页面并搜索他们想要查看其详细信息的学生/课程。
为了实现这一点,我想在路由期间进行一个backend/API调用。 API 响应将表明,即“millerh”是学生、课程还是两者都不是。 取决于我想导航到相应的组件,并传递名称student/course 以及组件。我想避免重定向,即从 myapp.com/millerh 到 myapp.com/students/millerh,以避免同一资源有多个有效路径。
如何从开箱即用的 angular 路由模块开始?
非常感谢任何提示和建议!
我认为 Angular router 无法区分 millerh 是学生还是 math1 是课程,我认为你应该选择类似的东西:
myapp.com/students/millerh
myapp.com/courses/math1
编辑
假设您的一个用户想要搜索一个学生,他将输入 myapp.com/students/<studentName>
,然后该应用将导航至 students
组件,而 studentName
将是可用作路由参数,然后您可以使用 ngOnInit
生命周期挂钩对后端的学生端点进行 API 调用。
编辑编号 2
无需在 URL 中键入 students/courses 的解决方案,但在 URL 解决后您仍然可以使用它们
假设您一开始不想区分学生路线和课程路线。
想象你的用户类型 myapp.com/<someValue>
,现在你不知道他在找什么,学生还是课程,一开始他会登陆你的根组件,在这个组件中你可以使用 ngOnInit
来拨打 API 电话。
首先对您的学生端点进行 API 调用,如果有学生,请让您的应用程序以编程方式导航至 myapp.com/students/<someValue>
.
如果找不到学生,请 API 调用您的课程端点,如果有课程,请让您的应用以编程方式导航至 myapp.com/courses/<someValue>
.
最终会有对 url 课程学生的引用,但对您的用户来说会更容易,因为他们可以直接键入 myapp.com/<someValue>
.
无需在 URL 中键入 students/courses 的解决方案,你也不会将它们放在最后的 URL 中
您可以将它们放在一个页面中,而不是将您的学生组件和您的课程放在两个不同的页面中,在您的情况下可能是根组件,而不是重定向到 students
或 course
,您可以根据哪个 API 调用返回值来显示一个或另一个。
好的,我找到了一个我非常喜欢的工作解决方案:它似乎工作得很好,而且感觉不太hack。它并不完全符合任何已发布的建议 - 但感谢所有回复和评论,因为它们确实帮助我找到了最终解决方案!
最终的解决方案在其核心中使用了一个实现 CanActivate 的守卫,结合守卫内部的 router.resetConfig()
和 router.navigate()
。
作为我的解决方案的入口点,我使用标准路由模块。它对我的用例仍然有用,因为有些组件具有单个静态路由。
文件:app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './features/home/home.component';
import { StudentListComponent} from './features/student-list/student-list.component';
import { CourseListComponent} from './features/course-list/course-list.component';
import { LoadingComponent } from './features/loading/loading.component';
import { NotFoundComponent } from './features/not-found/not-found.component';
import { DynamicRouteGuard } from './guards/dynamic-route.guard';
const routes: Routes = [
{
path: '/',
component: HomeComponent
},
{
path: 'students',
component: StudentListComponent
},
{
path: 'courses',
component: CourseListComponent
},
{
path: 'not-found',
component: NotFoundComponent
},
{
path: '**',
canActivate: [ DynamicRouteGuard ],
component: LoadingComponent,
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
路径 /、students、courses 和 not-found 是大多数 Angular 应用程序中的普通静态路由。任何与这些不匹配的路由都将被底部的通配符路由处理。该路由加载一个组件,该组件可能包含一个加载微调器。当 Guard 异步地对后端进行 API 调用以确定加载哪个组件时,它将是可见的。
文件:动态-route.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { EntityTypeService } from '../../services/entity-type.service';
import { IEntityTypeModel } from '../../models/entity-type.model';
import { EntityType } from '../../models/entity-type.enum';
import { StudentDetailComponent } from '../features/student-detail/student-detail.component';
import { CourseDetailComponent } from '../features/course-detail/course-detail.component';
@Injectable({
providedIn: 'root'
})
export class DynamicRouteGuard implements CanActivate {
constructor(
private entityTypeService : EntityTypeService,
private router : Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
// At this point, only routes with a single path element are considered valid routes.
if (route.url.length != 1) {
this.router.navigate(['not-found']);
return false;
}
let path = route.url[0].toString();
// Ask backend, what kind of entity the requested path matches to
this.entityTypeService.getEntityTypeForPath(path).subscribe(response => {
let entityTypeModel = response as IEntityTypeModel;
// If backend did not recognize path --> redirect to page not found component.
if (entityTypeModel.entityType === EntityType.Unknown) {
this.router.navigate(['not-found']);
}
// Build a new routes array. Slicing is required as wildcard route
// should be omitted from the new routes array (risk of endless loop)
let routes = this.router.config;
let newRoutes = routes.slice(0, routes.length - 1);
// Add a new route for the requested path to the correct component.
switch(entityTypeModel.entityType) {
case EntityType.Student:
newRoutes.push({ path: path, component: StudentDetailComponent, data: { resourceName: path } });
break;
case EntityType.Course:
newRoutes.push({ path: path, component: CourseDetailComponent, data: { resourceName: path } });
break;
default:
this.router.navigate(['not-found']);
return;
}
// Reload routes and navigate.
this.router.resetConfig(newRoutes);
this.router.navigate([path]);
});
// Guard always returns true and loads LoadingComponent while API
// request is being executed.
return true;
}
}
在守卫中,可以访问请求的路由,并且可以轻松注入 API 服务。使用该服务,后端在数据库中查找路径,并且 returns 一个枚举值指示它是学生、课程还是两者都不是。根据这一点,一个新的路由被添加到 Routes 数组,对于那个特定的 student/course 名称,链接到匹配的组件。之后重新加载路由,路由器可以直接导航到正确的组件。