web-dev-qa-db-ger.com

Übergabe von Daten an untergeordnete Komponenten "Router-Outlet" (Winkel 2)

Ich habe eine übergeordnete Komponente, die zum Server geht und ein Objekt abruft.

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

Und in (einer von mehreren) meiner Kinderanzeige

export class ChildDisplay implements OnInit{

    @Input()
    node: Node;

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

}

Es scheint nicht so zu sein, als ob ich einfach Daten in den Router-Ausgang injizieren könnte. Anscheinend erhalte ich den Fehler in der Webkonsole ...

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

Das macht zwar etwas Sinn, aber wie würde ich folgendes machen ....

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

Es scheint nicht so, als würden Router-Outlets auf dieselbe Weise funktionieren.

57
Zack

Die einzige Möglichkeit ist, einen gemeinsam genutzten Dienst zu verwenden.

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

ist einfach ungültig. Die vom Router hinzugefügte Komponente wird zu <router-outlet> als gleichgeordnetes Element hinzugefügt und ersetzt es nicht.

Siehe auch https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-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);
    }
}
56

Günters Antwort ist großartig, ich möchte nur einen anderen Weg aufzeigen, ohne Observables zu verwenden. 

Hier müssen wir jedoch bedenken, dass diese Objekte als Referenz übergeben werden. Wenn Sie also das Objekt im untergeordneten Objekt bearbeiten möchten und nicht das übergeordnete Objekt beeinflussen möchten, würde ich vorschlagen, die Lösung von Günther zu verwenden. Aber wenn es egal ist oder eigentlich gewünschtes Verhalten ist, würde ich folgendes vorschlagen.

@Injectable()
export class SharedService {

    sharedNode = {
      // properties
    };
}

In Ihrem Elternteil können Sie den Wert zuweisen:

this.sharedService.sharedNode = this.node;

Fügen Sie in Ihren Kindern (UND-Eltern) den gemeinsam genutzten Dienst in Ihrem Konstruktor ein. Denken Sie daran, den Dienst auf Anbieterebene auf Modulebene bereitzustellen, wenn Sie einen Singleton-Dienst für alle Komponenten in diesem Modul wünschen. Alternativ können Sie den Dienst einfach in das Provider-Array im übergeordneten only aufnehmen. Dann haben Eltern und Kinder die gleiche Instanz des Dienstes.

node: Node;

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

Und wie Newman freundlich zeigt, können Sie auch this.sharedService.sharedNode in der HTML-Vorlage oder einen Getter haben:

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

Bedienung:

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

Komponente:

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--);
  }
}
5
egor.xyz

Es gibt drei Möglichkeiten, Daten von Eltern an Kinder zu übergeben

  1. Durch teilbaren Dienst: Sie sollten die Daten, die Sie mit den Kindern teilen möchten, in einem Dienst speichern
  2. Über Children Router Resolver, wenn Sie andere Daten erhalten müssen

    this.data = this.route.snaphsot.data['dataFromResolver'];
    
  3. Über Parent Router Resolver, wenn Sie dieselben Daten von einem übergeordneten Computer erhalten müssen

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

Note1: Sie können über Resolver hier lesen. Es gibt auch ein Beispiel für einen Resolver und wie der Resolver im Modul registriert und anschließend Daten vom Resolver in die Komponente abgerufen werden. Die Resolver-Registrierung ist für Eltern und Kind gleich.

Note2: Sie können etwas über ActivatedRoutehier erfahren, um Daten vom Router zu erhalten

1
Rzv Razvan

Nach dieser Frage können Sie in Angular 7.2 Daten mit dem Verlaufsstatus von einem Elternteil an ein Kind übergeben. So kann man sowas machen

Senden:

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

Abrufen:

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

Aber seien Sie vorsichtig, um konsequent zu sein. Angenommen, Sie möchten eine Liste in der linken Leiste und die Details des ausgewählten Elements in der rechten Leiste mithilfe eines Router-Ausgangs anzeigen. So etwas wie:


Punkt 1 (x) | ..............................................

Punkt 2 (x) | ...... Ausgewählte Artikeldetails .......

Punkt 3 (x) | ..............................................

Punkt 4 (x) | ..............................................


Angenommen, Sie haben bereits einige Elemente angeklickt. Durch Klicken auf die Zurück-Schaltflächen des Browsers werden die Details des vorherigen Elements angezeigt. Aber was ist, wenn Sie in der Zwischenzeit auf das (x) geklickt und dieses Element aus Ihrer Liste gelöscht haben? Wenn Sie dann den Rückklick ausführen, werden die Details eines gelöschten Elements angezeigt.

0
MTZ