web-dev-qa-db-fra.com

Angular router: comment passer des données au module de chargement paresseux?

J'ai les chemins de routage suivants pour un module de mon Angular app:

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: 'documents',
                data: { myObject: MyConstants.OPTION_ONE },
                children: [
                    {
                        path: ':ID_DOC',
                        children: [
                            { path: 'edit', component: EditDocumentComponent },
                            { path: '', component: DocumentDetailsComponent },
                        ]
                    },
                    { path: 'add', component: AddDocumentComponent },
                    { path: '', component: DocumentsListComponent }
                ]
            }
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class DocumentsManagementRoutingModule {
}

Comme vous pouvez le voir, j'utilise la propriété data pour transmettre des données à chaque chemin dans les "documents", donc je peux les obtenir à partir de n'importe quel composant déclaré dans les chemins de routage:

Par exemple, voici comment obtenir des données dans DocumentDetailsComponent:

export class DocumentDetailsComponent implements OnDestroy {
    private obsData: Subscription;
    private option: any;

    constructor(private route: ActivatedRoute) {
        this.obsData = this.route.data.subscribe(data => {
            this.option = data['myObject'];
        });
    }

    ngOnDestroy(): void {
        this.obsData.unsubscribe();
    }
}

Maintenant, j'ai changé la structure de routage de l'application entière et j'appelle le module ci-dessus à partir d'autres modules, en chargement paresseux, en utilisant l'attribut loadChildren. Et je passe des données de la même manière:

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: 'users',
                loadChildren: 'app/documents/documents.module#DocumentsModule',
                data: { myObject: MyConstants.OPTION_ONE }},
            {
                path: ':ID_USER',
                children: [
                    { path: 'edit', component: EditUserComponent },
                    { path: '', component: UserDetailsComponent },
                ]
            },
            { path: 'add', component: AddUserComponent },
            { path: '', component: UserListComponent }
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class UsersManagementRoutingModule {
}

Et j'ai fait la même chose pour tous les autres modules qui appellent DocumentsManagementRoutingModule, en changeant la propriété myObject en MyConstants.OPTION_TWO, MyConstants.OPTION_THREE et ainsi de suite, selon mes besoins.

Puis, comme je ne connais pas le module et son chemin d'accès associé qui appelle mon module de chargement différé, comment obtenir la propriété data à partir du module appelant?

17
smartmouse

Vous pouvez parcourir les itinéraires parents à l'aide de enabledRoute.pathFromRoot et obtenir les données de l'ancêtre le plus proche qui les a disponibles. Quelque chose comme ça semble fonctionner:

  ngOnInit(): void {
    let idx = this.activatedRoute.pathFromRoot.length - 1;
    while(this.sharedData == null && idx > 0){
      this.sub = this.activatedRoute.pathFromRoot[idx].data.subscribe(subData => {

        if(subData.id)
          this.sharedData = subData;

        console.log('shared data', this.sharedData);
      });
      idx--;
    }
  }

https://plnkr.co/edit/K5Rb1ZvTvSQNM6tOLeFp

6
rusmus

Je pense que je peux comprendre sur quoi porte la question.


Problème

Voici le graphe de routage du plunker @smartmouse fourni.

- home
  - shop
  - contact
    - map
  - about

Un objet data est configuré sur la configuration de la route home. Les routes enfants directes peuvent accéder à cet objet de données. Le problème est que l'enfant non direct map veut accéder à l'objet data, mais apparemment, il ne le peut pas.

Et nous pouvons savoir que @smartmouse veut pousser encore plus loin - les routes enfants imbriquées non directes peuvent accéder aux données de l'ancêtre .

Pourquoi ça ne peut pas?

Voir le plongeur que j'ai modifié. https://plnkr.co/edit/FA7mGmspUXHhU8YvgDpT

Vous pouvez voir que je définis un composant enfant supplémentaire DefaultComponent pour contact. Il montre que c'est l'enfant direct et par défaut de la route contact, ce qui peut être interprété car c'est aussi l'enfant direct de la route supérieure home. Ainsi, il peut accéder à l'objet data.

Solution

Regardez à nouveau le plongeur fourni par moi.

REMARQUE: les packages Angular que j'utilise sont v4.3.0

Approche n ° 1 - Paramètres de requête

Je définis certains paramètres de requête dans home.component.ts pour contact route. Vous pouvez voir comment l'utiliser.

Avantages :

  • vous pouvez accéder aux paramètres de requête sur n'importe quel niveau de routes.
  • fonctionne bien avec les modules lazyload

Inconvénients :

  • vous ne pouvez pas définir de paramètres de requête dans la configuration de route.

    Mais vous pouvez utiliser des crochets de cycle de vie de route pour les définir pour les routes ancêtres cibles

Approche n ° 2 - service

Définissez un service de partage de données au niveau supérieur de l'application jouant en tant que motif singleton. En outre, utilisez un util pour l'empêcher d'être lancé deux fois. Ensuite, vous pouvez y mettre des données et les récupérer n'importe où.

Avantages :

  • global visible via DI;
  • fonctionne bien avec les modules lazyload

Inconvénients :

  • vous ne pouvez pas mettre à jour les données dans la configuration de l'itinéraire.
  • vous devez définir les données ailleurs. Si vous ne pouvez pas contrôler la source, cela peut être un problème.

Approche n ° 3 - résolution d'itinéraire

Quelqu'un peut découvrir que j'ai également défini resolve exemple de code dans le plunker. C'est pour montrer qu'il a le même comportement que data dans la configuration de route, sauf qu'il s'agit en fait de la récupération dynamique de données.

https://vsavkin.com/angular-router-understanding-router-state-7b5b95a12eab#54
La propriété data est utilisée pour passer un objet fixe à une route activée. Il ne change pas pendant la durée de vie de l'application. La propriété de résolution est utilisée pour les données dynamiques.

Prenons l'exemple du plunkr de @ smartmouse.

Nous avons data défini dans la configuration de la route 'home'. Nous pouvons définir un résolveur de données dans ContactModule pour l'itinéraire par défaut du contact, et proxy les données transmises à partir de l'itinéraire supérieur. Tous ses itinéraires enfants directs peuvent alors accéder à l'objet de données résolu.

Avantages :

  • fonctionne bien avec n'importe quel niveau de routes imbriquées
  • fonctionne bien avec les modules lazyload

Inconvénients :

  • Vous devrez peut-être déclarer cette propriété de résolution dans chaque itinéraire parent dont les itinéraires enfants souhaitent accéder à ces données. C'est du sale boulot.

Il n'y a pas de solution parfaite et universelle, pour l'instant, avec une utilisation courante d'Angular. Quelqu'un devrait peser le pour et le contre et choisir le bon.

10
e-cloud

Pourquoi n'utilisez-vous pas le service pour partager les données entre les modules ou les composants. Vous pouvez avoir ce service importé chez le fournisseur de module principal et donc être utilisé dans tous les autres modules (module de chargement différé) et partager les données.

Le service peut avoir des fonctions pour définir et obtenir des valeurs et vous pouvez donc utiliser ces fonctions dans les services pour obtenir vos données requises

0
Kowsalya
@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: 'users',
                loadChildren: 'app/documents/documents.module#DocumentsModule',
                resolve : {
                     data: DataResolver
                }
            {
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class UsersManagementRoutingModule {
}


@Injectable()
export class DataResolverimplements Resolve<Data> {
  resolve() {
    return this.serice.getData();
  }
}
0
Yoav Schniederman