Angularルートのセット、エンティティのリスト、そのようなエンティティの作成と既存のエンティティの編集のための2つの子ルートがあります。エンティティのリストにはresolver
を付加します。これらのルートは次のように要約できます。これらのルートがコードでどのように記述されているかについては、さらに下を参照してください。
/items
/items/create
/items/:itemId/edit
ただし、私が/items/create
、アイテムを正常に作成し、「[戻る]」に移動して/items
または編集ルート、または/
は、リゾルバが期待したように更新されたデータをフェッチする結果にはなりません。 これは、runGuardsAndResolvers
プロパティが "always"に設定されているにもかかわらずです。 私の理解 は、このプロパティが私が探している機能を有効にするはずであることです。
これはなぜですか、そして私が探している機能をどのように有効にすることができますか?コンポーネントのルーターイベントのサブスクライブやロジックの複製などを行わずに.
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)
);
}
}
これは、Resolver
をどのように使用すべきかではありません。
Resolver
は、必要なデータが存在することがルートにとって必要不可欠な場合にのみ使用してください。したがって、リゾルバーは、専用のデータのルートがあり、コンポーネントのロードを続行する前にこのデータが存在することを確認したい場合に意味があります。
Item Appを例に取り、ユーザーの視点から問題に直面しましょう。
ユーザーが/items
に移動すると、最初に表示されるものは何もありません。これは、ユーザーがコンポーネントに到達する前に、リゾルバーがすべてのアイテムをフェッチしているためです。リゾルバーがAPIからすべてのアイテムをフェッチした後にのみ、ユーザーはItemsComponent
に委任されます。
しかし、これは必須ではなく、ユーザーエクスペリエンスも悪いです。
ユーザーを直接ItemsComponent
に委任しないのはなぜですか。たとえば、たくさんのボタンとおしゃれなCSSを備えた素晴らしいテーブルがある場合、Service
がAPIからデータをフェッチしている間に、これらの要素をレンダリングする時間をアプリに与えることができます。データがロードされていることをユーザーに示すには、データが到着するまで、テーブル内にニースprogress-spinner(-bar)を表示します。
こっちも一緒。ユーザーは、Resolver
がCreateComponent
に到達する前に、APIからすべてのデータをフェッチするまで待機する必要があります。これは、ユーザーだけがアイテムを作成できる場合にのみ、すべてのアイテムをフェッチするのはやり過ぎであることは明らかです。したがって、Resolver
は必要ありません。
それはリゾルバーにとって最高の場所です。ユーザーは、アイテムが存在する場合にのみ、このコンポーネントにルーティングできる必要があります。しかし、子ルートの1つがアクティブ化されたときにすべてのアイテムをフェッチするようにリゾルバーを定義すると、ユーザーは以前のルートと同じように悪いユーザーエクスペリエンスに直面します。
ルートから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
}
}
]
}
];
キャッシュのように最後にフェッチされたアイテムを保持するBehaviorSubjectをItemsService
に定義できます。ユーザーがcreateまたはeditからItemsComponent
にルーティングするたびに、アプリはキャッシュされたアイテムを即座にレンダリングし、その間、サービスはバックグラウンドでアイテムを同期できます。
私は小さな実用的なサンプルアプリを実装しました: https://stackblitz.com/github/SplitterAlex/stackoverflow-48640721
Resolver
は、アイテム編集ルートでのみ意味があります。
Resolver
は慎重に使用してください。