我有一组Angular路由,带有实体列表,有两条子路由,用于创建这样的实体和编辑现有实体。实体列表附加了resolver
,以便在显示组件之前预取组件的数据。这些路由可以总结如下,进一步了解如何在代码中描述这些路由。
/items
/items/create
/items/:itemId/edit
但是,如果我在/items/create
,并且成功创建了一个项目,则“返回”/items
或任何编辑路线,甚至返回/
都不会导致我解析器像我期望的那样获取更新的数据。 尽管将runGuardsAndResolvers
属性设置为“始终”。 My understanding是这个属性应该启用我正在寻找的功能。
为什么会这样,以及如何启用我正在寻找的功能,没有执行类似订阅组件中的路由器事件和复制逻辑的操作。
const itemRoutes: Routes = [
{
path: '', // nb: this is a lazily loaded module that is itself a child of a parent, the _actual_ path for this is `/items`.
runGuardsAndResolvers: 'always',
component: ItemsComponent,
data: {
breadcrumb: 'Items'
},
resolve: {
items: ItemsResolver
},
children: [
{
path: 'create',
component: CreateItemComponent,
data: {
breadcrumb: 'Create Item'
}
},
{
path: ':itemId/edit',
component: EditOrArchiveItemComponent,
data: {
breadcrumb: 'Editing Item :item.name'
},
resolve: {
item: ItemResolver
}
}
]
}
];
@Injectable()
export class ItemsResolver implements Resolve<ItemInIndex[]> {
public constructor(public itemsHttpService: ItemsHttpService, private router: Router) {}
public resolve(ars: ActivatedRouteSnapshot, rss: RouterStateSnapshot): Observable<ItemInIndex[]> {
return this.itemsHttpService.index().take(1).map(items => {
if (items) {
return items;
} else {
this.router.navigate(['/']);
return null;
}
});
}
}
(根据要求发布)
@Injectable()
export class ItemsHttpService {
public constructor(private apollo: Apollo) {}
public index(): Observable<ItemInIndex[]> {
const itemsQuery = gql`
query ItemsQuery {
items {
id,
name
}
}
`;
return this.apollo.query<any>({
query: itemsQuery
}).pipe(
map(result => result.data.items)
);
}
}
答案 0 :(得分:8)
这是不您应该如何使用Resolver
。
只有当您的路线对所需数据存在至关重要时,才应使用Resolver
。因此,当您拥有专用数据路径时,解析器是有意义的,并且您希望在继续加载组件之前确保此数据存在。
让我们以您的项目应用为例,从用户的角度来看问题。
用户导航到/items
,他首先会看到的是什么。这是因为解析器在用户可以到达组件之前获取所有项目。只有在解析器从api中获取所有项目后,才会将用户委派给ItemsComponent
。
但这不是必要的和糟糕的用户体验。
为什么不直接将用户委托给ItemsComponent
。例如,如果您有一个包含大量按钮和精美炫酷css的精彩表格,那么当您的Service
从api中获取数据时,您可以给予应用时间渲染这些元素。要指示正在加载数据的用户,您可以在表格中显示一个漂亮的 progress-spinner(-bar),直到数据到达。
同样在这里。用户必须等到Resolver
从api获取所有数据,然后才能到达CreateComponent
。应该清楚的是,只有用户可以创建项目才能获取所有项目。所以不需要Resolver
这是解析器的最佳位置。当且仅当项目存在时,用户才能够路由到此组件。但是,当您定义一个解析器以在其中一个子路由被激活时获取所有项目时,用户将面临与先前路由相同的不良用户体验。
从路线中删除ItemsResolver。
const routes: Routes = [
{
path: '',
component: ItemsComponent,
children: [
{
path: '',
component: ItemsListComponent,
data: {
breadcrumb: 'Items'
},
},
{
path: 'create',
component: CreateItemComponent,
data: {
breadcrumb: 'Create Item'
},
},
{
path: ':itemId/edit',
component: EditOrArchiveItemComponent,
data: {
breadcrumb: 'Editing Item :item.name'
},
resolve: {
item: ItemResolverService
}
}
]
}
];
您可以在ItemsService
中定义一个BehaviorSubject,它将您最后获取的项目保存为缓存。每当用户从创建或编辑返回到ItemsComponent
时,您的应用都可以立即呈现缓存的项目,同时您的服务可以同步背景
我实现了一个小工作示例App: https://stackblitz.com/github/SplitterAlex/stackoverflow-48640721
Resolver
仅对编辑项路线有意义。
谨慎使用Resolver
!