133 votes

Passage de données dans des composants enfants "routeur-prise" (angular 2)

J'ai un composant parent, qui passe pour 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 plusieurs) mon enfant d'affichage

export class ChildDisplay implements OnInit{

    @Input()
    node: Node;

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

}

Il ne semble pas que la pensée que je peux juste injecter des données dans le routeur de sortie. Il semble que je reçois le message d'erreur dans la console web...

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

Ce peu de sens, mais comment pourrais-je faire ce qui suit....

1) Grab the "node" data from the server, from within the parent component
2) Pass the data I have retrieved from the server into the child router-outlet

Il ne semble pas comme routeur-les prises de la même façon.

97voto

Günter Zöchbauer Points 21340

Le seul moyen est d'utiliser un service partagé.

<router-outlet [node]="..."></router-outlet> 

est tout simplement pas valide. Le composant est ajouté par le routeur est ajouté en tant que frère de l' <router-outlet> et ne la remplace pas.

Voir aussi https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectionnel-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);
    }
}

52voto

AJT_82 Points 30605

Günters réponse est grande, je veux juste souligner une autre façon sans l'aide des Observables.

Ici nous cependant de se rappeler que ces objets sont passés par référence, donc, si vous voulez faire un peu de travail sur l'objet dans l'enfant et de ne pas affecter l'objet parent, je conseille de Günther solution. Mais si elle n'a pas d'importance, ou est en fait le comportement désiré, je dirais que la suivante.

@Injectable()
export class SharedService {

    sharedNode = {
      // properties
    };
}

Dans votre parent, vous pouvez affecter la valeur:

this.sharedService.sharedNode = this.node;

Et vos enfants (ET de parents), injecter le Service partagé dans votre constructeur. N'oubliez pas de fournir le service au niveau du module fournisseurs de tableau, si vous voulez un singleton service de tous les composants de ce module. Sinon, il suffit d'ajouter le service dans les fournisseurs de tableau dans le parent seul, alors le parent et l'enfant partagent la même instance de service.

node: Node;

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

Et comme newman aimablement fait, vous pouvez également avoir d' this.sharedService.sharedNode dans le modèle html ou un getter:

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

10voto

egor.xyz Points 1168

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

10voto

Rzv Razvan Points 368

Il y a 3 façons de transmettre les données d'un Parent à ses Enfants

  1. Par partageable service : vous devez les stocker dans un service de données que vous souhaitez partager avec les enfants
  2. À travers les Enfants Routeur Résolveur si vous devez recevoir des données différentes

    this.data = this.route.snaphsot.data['dataFromResolver'];
    
  3. Parent Routeur Résolveur si vous avez de recevoir les mêmes données de parent

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

Note 1: Vous pouvez lire sur résolveur ici. Il est aussi un exemple de programme de résolution et comment faire pour enregistrer le programme de résolution dans le module, puis récupérer des données à partir de résolution dans le composant. Le programme de résolution de l'enregistrement est la même sur le parent et l'enfant.

Note2: Vous pouvez lire sur ActivatedRoute ici pour être en mesure d'obtenir des données à partir de routeur

3voto

MTZ Points 86

Suite à cette question, dans Angulaire 7.2 vous pouvez passer des données d'un parent à l'enfant à l'aide de l'histoire de l'état. Si vous pouvez faire quelque chose comme

Envoyer:

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

Récupérer:

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

Mais attention, pour être cohérent. Par exemple, supposons que vous souhaitez afficher une liste sur le côté gauche de la barre et les détails de l'élément sélectionné sur la droite à l'aide d'un routeur de sortie. Quelque chose comme:


Le point 1 (x) | ..............................................

Article 2 (x) | ......Détails De L'Élément Sélectionné.......

Article 3 (x) | ..............................................

Article 4 (x) | ..............................................


Maintenant, supposons que vous avez déjà cliqué sur certains éléments. En cliquant sur le retour du navigateur boutons pour afficher les détails de l'élément précédent. Mais que faire si, en attendant, vous avez cliqué sur le (x) et de supprimer à partir de votre liste de cet élément? Puis la mise à retour sur, va vous montrer les détails d'un élément supprimé.

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