158 votes

Passage de données dans les composants enfants "routeur-sortie".

J'ai un composant parent qui va sur le serveur et récupère un objet :

// parent component

@Component({
    selector : 'node-display',
    template : `
        <router-outlet [node]="node"></router-outlet>
    `
})

export class NodeDisplayComponent implements OnInit {

    node: Node;

    ngOnInit(): void {
        this.nodeService.getNode(path)
            .subscribe(
                node => {
                    this.node = node;
                },
                err => {
                    console.log(err);
                }
            );
    }

Et dans l'une des nombreuses expositions d'enfants :

export class ChildDisplay implements OnInit{

    @Input()
    node: Node;

    ngOnInit(): void {
        console.log(this.node);
    }

}

Il ne semble pas que je puisse simplement injecter des données dans le fichier router-outlet . Il semble que je reçoive l'erreur dans la console web :

Can't bind to 'node' since it isn't a known property of 'router-outlet'.

Cela a du sens, mais comment puis-je faire ce qui suit ?

  1. Récupérer les données du "nœud" du serveur, à partir du composant parent. parent ?
  2. Transférer les données que j'ai récupérées du serveur dans la sortie du routeur enfant ?

Il ne semble pas que router-outlets fonctionnent de la même manière.

108voto

Günter Zöchbauer Points 21340
<router-outlet [node]="..."></router-outlet> 

est tout simplement invalide. Le composant ajouté par le routeur est ajouté en tant que frère ou sœur de <router-outlet> et ne le remplace pas.

Voir aussi https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

@Injectable() 
export class NodeService {
  private node:Subject<Node> = new BehaviorSubject<Node>([]);

  get node$(){
    return this.node.asObservable().filter(node => !!node);
  }

  addNode(data:Node) {
    this.node.next(data);
  }
}

@Component({
    selector : 'node-display',
    providers: [NodeService],
    template : `
        <router-outlet></router-outlet>
    `
})
export class NodeDisplayComponent implements OnInit {
    constructor(private nodeService:NodeService) {}
    node: Node;
    ngOnInit(): void {
        this.nodeService.getNode(path)
            .subscribe(
                node => {
                    this.nodeService.addNode(node);
                },
                err => {
                    console.log(err);
                }
            );
    }
}

export class ChildDisplay implements OnInit{
    constructor(nodeService:NodeService) {
      nodeService.node$.subscribe(n => this.node = n);
    }
}

0 votes

Peut-on l'utiliser pour donner un identifiant à l'enfant ? J'ai essayé de changer tous les node où il s'agit d'un type de string et ça ne semble pas fonctionner ou je fais quelque chose de mal.

0 votes

Vous pouvez transmettre n'importe quelle donnée au composant enfant, mais ce dernier doit définir lui-même l'identifiant. Vous pouvez essayer d'obtenir un ElementRef à partir d'un événement de la sortie du routeur pour l'utiliser pour définir l'id mais je ne sais pas par cœur si ou comment faire cela (seulement sur mon téléphone)

0 votes

Il est possible de transférer des données via la directive routeur-outlet. Nous pouvons utiliser l'événement "activate" pour cela. Pour plus de détails, lisez mon article Voir aussi angular.io/guide/ Voir aussi linkedin.com/pulse/

54voto

AJT_82 Points 30605

La réponse de Günters est excellente, je veux juste signaler un autre moyen sans utiliser les Observables.

Il faut cependant se rappeler que ces objets sont transmis par référence, donc si vous voulez travailler sur l'objet dans l'enfant sans affecter l'objet parent, je vous suggère d'utiliser la solution de Günther. Mais si cela n'a pas d'importance, ou si c'est en fait comportement souhaité Je vous suggère ce qui suit.

@Injectable()
export class SharedService {

    sharedNode = {
      // properties
    };
}

Dans votre parent, vous pouvez attribuer la valeur :

this.sharedService.sharedNode = this.node;

Et dans vos enfants (ET parent), injectez le Service partagé dans votre constructeur. N'oubliez pas de fournir le service dans le tableau des fournisseurs au niveau du module si vous voulez un service singleton sur tous les composants de ce module. Alternativement, ajoutez simplement le service dans le tableau des fournisseurs du parent. sólo alors le parent et l'enfant partageront la même instance de service.

node: Node;

ngOnInit() {
    this.node = this.sharedService.sharedNode;    
}

Et comme Newman l'a gentiment fait remarquer, vous pouvez également avoir this.sharedService.sharedNode dans le modèle html ou un getter :

get sharedNode(){
  return this.sharedService.sharedNode;
}

7 votes

Vous pouvez/devriez vous lier directement à sharedService.sharedNode dans le html. De cette façon, les mises à jour de sharedNode seront synchronisées.

12voto

Rzv Razvan Points 368

Il existe trois façons de transmettre des données des parents aux enfants.

  1. Par le biais d'un service partageable : vous devez stocker dans un service les données que vous souhaitez partager avec les enfants.

  2. Par le biais du Children Router Resolver si vous devez recevoir différentes données

    this.data = this.route.snaphsot.data['dataFromResolver'];
  3. Par le biais du Parent Router Resolver si vous devez recevoir les mêmes données du parent

    this.data = this.route.parent.snaphsot.data['dataFromResolver'];

Note1 : Vous pouvez lire sur le résolveur aquí . Il y a aussi un exemple de resolver et comment enregistrer le resolver dans le module et ensuite récupérer les données du resolver dans le composant. L'enregistrement du résolveur est le même pour le parent et l'enfant.

Note2 : Vous pouvez lire sur ActivatedRoute aquí pour pouvoir obtenir des données du routeur

11voto

egor.xyz Points 1168

Service :

import {Injectable, EventEmitter} from "@angular/core";    

@Injectable()
export class DataService {
onGetData: EventEmitter = new EventEmitter();

getData() {
  this.http.post(...params).map(res => {
    this.onGetData.emit(res.json());
  })
}

Composant :

import {Component} from '@angular/core';    
import {DataService} from "../services/data.service";       

@Component()
export class MyComponent {
  constructor(private DataService:DataService) {
    this.DataService.onGetData.subscribe(res => {
      (from service on .emit() )
    })
  }

  //To send data to all subscribers from current component
  sendData() {
    this.DataService.onGetData.emit(--NEW DATA--);
  }
}

5voto

MTZ Points 86

Suivant este Dans Angular 7.2, vous pouvez transmettre des données du parent à l'enfant en utilisant l'historique. Vous pouvez donc faire quelque chose comme

Envoyez :

this.router.navigate(['action-selection'], { state: { example: 'bar' } });

Récupérer :

constructor(private router: Router) {
  console.log(this.router.getCurrentNavigation().extras.state.example);
}

Mais veillez à rester cohérent. Par exemple, supposons que vous souhaitiez afficher une liste sur une barre latérale gauche et les détails de l'élément sélectionné sur la droite en utilisant un router-outlet. Quelque chose comme :


Élément 1 (x) | ..............................................

Article 2 (x) | ......Détails de l'article sélectionné.......

Point 3 (x) | ..............................................

Point 4 (x) | ..............................................


Supposons maintenant que vous ayez déjà cliqué sur certains éléments. Si vous cliquez sur les boutons de retour des navigateurs, les détails de l'élément précédent s'afficheront. Mais que se passe-t-il si, entre-temps, vous avez cliqué sur le (x) et supprimé cet élément de votre liste ? Si vous cliquez sur le bouton "retour", les détails de l'élément supprimé s'afficheront.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X