Angular解析器没有更新或重新获取数据,尽管`runGuardsAndResolvers`设置为'always'?

时间:2018-02-06 10:26:38

标签: angular angular-routing angular-resolver

我有一组Angular路由,带有实体列表,有两条子路由,用于创建这样的实体和编辑现有实体。实体列表附加了resolver,以便在显示组件之前预取组件的数据。这些路由可以总结如下,进一步了解如何在代码中描述这些路由。

  • index:/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
                }
            }
        ]
    }
];

ItemsResolver

@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;
            }
        });
    }
}

ItemsHttpService

(根据要求发布)

@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)
        );
    }
}

1 个答案:

答案 0 :(得分:8)

首先。

这是您应该如何使用Resolver

只有当您的路线对所需数据存在至关重要时,才应使用Resolver。因此,当您拥有专用数据路径时,解析器是有意义的,并且您希望在继续加载组件之前确保此数据存在。

让我们以您的项目应用为例,从用户的角度来看问题。

/项

用户导航到/items,他首先会看到的是什么。这是因为解析器在用户可以到达组件之前获取所有项目。只有在解析器从api中获取所有项目后,才会将用户委派给ItemsComponent

但这不是必要的和糟糕的用户体验。

为什么不直接将用户委托给ItemsComponent。例如,如果您有一个包含大量按钮和精美炫酷css的精彩表格,那么当您的Service从api中获取数据时,您可以给予应用时间渲染这些元素。要指示正在加载数据的用户,您可以在表格中显示一个漂亮的 progress-spinner(-bar),直到数据到达。

/项目/创建

同样在这里。用户必须等到Resolver从api获取所有数据,然后才能到达CreateComponent。应该清楚的是,只有用户可以创建项目才能获取所有项目。所以不需要Resolver

/项目/:的itemId /编辑

这是解析器的最佳位置。当且仅当项目存在时,用户才能够路由到此组件。但是,当您定义一个解析器以在其中一个子路由被激活时获取所有项目时,用户将面临与先前路由相同的不良用户体验。

解决方案

从路线中删除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