web-dev-qa-db-fra.com

Angular angulaire ne met pas à jour ou ne récupère pas les données, bien que `runGuardsAndResolvers` soit réglé sur 'toujours'?

J'ai un ensemble de Angular, avec une liste d'entités, avec deux routes enfants pour la création d'une telle entité et l'édition d'une entité existante. La liste d'entités a un resolver qui lui est attaché pour pré-extraire les données du composant avant de l'afficher. Ces routes peuvent être résumées comme suit, voir plus loin comment ces routes sont décrites dans le code.

  • index: /items
  • créer: /items/create
  • éditer: /items/:itemId/edit

Cependant, si je suis à /items/create, et créer un élément avec succès, en naviguant "retour" vers /items ou n'importe quel itinéraire d'édition, ou même revenir à / ne permettra pas à mon résolveur de récupérer les données mises à jour comme je m'y attendais. Ceci malgré le fait que la propriété runGuardsAndResolvers soit "toujours" . Ma compréhension est que cette propriété devrait permettre la fonctionnalité que je recherche.

Pourquoi cela et comment puis-je activer la fonctionnalité que je recherche, sans faire quelque chose comme s'abonner aux événements du routeur dans mon composant et dupliquer la logique.

Itinéraires

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

(Affichage sur demande)

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

Tout d'abord.

Ce n'est pas comment utiliser un Resolver.

Vous ne devez utiliser un Resolver que s'il est absolument nécessaire pour votre itinéraire que les données nécessaires existent. Un résolveur a donc un sens lorsque vous avez un itinéraire pour une donnée dédiée et que vous voulez vous assurer que ces données existent avant de continuer avec le chargement du composant.

Prenons votre Item App comme exemple et affrontons le problème du point de vue de l'utilisateur.

/articles

L'utilisateur accède à /items et ce qu'il va voir en premier n'est rien. En effet, le résolveur récupère tous les éléments avant que l'utilisateur puisse atteindre le composant. Ce n'est qu'après que le résolveur a récupéré tous les éléments de l'API que l'utilisateur est délégué au ItemsComponent.

Mais ce n'est pas une expérience utilisateur nécessaire et mauvaise.

Pourquoi ne pas déléguer directement l'utilisateur à ItemsComponent. Si vous avez par exemple une table impressionnante avec beaucoup de boutons et des CSS sympas, vous pouvez donner à votre application le temps de rendre ces éléments pendant que votre Service récupère les données de l'API. Pour indiquer à l'utilisateur le chargement des données, vous pouvez afficher un Nice progress-spinner (-bar) à l'intérieur du tableau jusqu'à ce que les données arrivent.

/ items/create

Pareil ici. L'utilisateur doit attendre que le Resolver récupère toutes les données de votre API avant de pouvoir atteindre le CreateComponent. Il doit être clair que c'est une exagération pour récupérer tous les éléments, seul l'utilisateur peut créer un élément. Il n'y a donc pas besoin d'un Resolver

/ items /: itemId/edit

C'est le meilleur endroit pour un résolveur. L'utilisateur doit pouvoir router vers ce composant si et seulement si l'élément existe. Mais comme vous avez défini un résolveur pour récupérer tous les éléments lorsque l'un de vos itinéraires enfants est activé, l'utilisateur fait face à la même mauvaise expérience utilisateur qu'avec les itinéraires précédents.

Solution

Supprimez le ItemsResolver de vos itinéraires.

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
          }
        }
      ]
  }
];

Vous pouvez définir un BehaviorSubject dans votre ItemsService qui contient vos derniers éléments récupérés comme un cache. Chaque fois qu'un utilisateur recule de - créer ou éditez vers ItemsComponent votre application peut immédiatement afficher les éléments mis en cache et en attendant, votre service peut synchroniser les éléments en arrière-plan.

J'ai implémenté un petit exemple d'application: https://stackblitz.com/github/SplitterAlex/stackoverflow-48640721

Conclusion

Un Resolver n'a de sens que sur l'itinéraire de modification des éléments.

Utilisez Resolver avec prudence!

10
SplitterAlex