route navigate injection example dependency angular dependency-injection angular2-routing

angular - navigate - Transferencia de datos a componentes secundarios de "salida de enrutador"



router.navigate angular 5 (5)

Servicio:

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

Componente:

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

Tengo un componente principal que va al servidor y busca un objeto:

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

Y en una de varias pantallas para niños:

export class ChildDisplay implements OnInit{ @Input() node: Node; ngOnInit(): void { console.log(this.node); } }

No parece que pueda simplemente inyectar datos en la router-outlet del router-outlet . Parece que aparece el error en la consola web:

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

Esto tiene sentido, pero ¿cómo haría lo siguiente?

  1. ¿Tomar los datos del "nodo" del servidor, desde dentro del componente principal?
  2. ¿Pasar los datos que he recuperado del servidor a la salida del enrutador secundario?

No parece que router-outlets funcionen de la misma manera.


Después de this pregunta, en Angular 7.2 puede pasar datos de padre a hijo utilizando el estado del historial. Entonces puedes hacer algo como

Enviar:

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

Recuperar:

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

Pero tenga cuidado de ser consistente. Por ejemplo, suponga que desea mostrar una lista en una barra lateral izquierda y los detalles del elemento seleccionado a la derecha utilizando una salida de enrutador. Algo como:

Artículo 1 (x) | ..............................................

Artículo 2 (x) | ...... Detalles del elemento seleccionado .......

Artículo 3 (x) | ..............................................

Artículo 4 (x) | ..............................................

Ahora, suponga que ya ha hecho clic en algunos elementos. Al hacer clic en los botones de retroceso de los navegadores, se mostrarán los detalles del elemento anterior. Pero, ¿qué sucede si, mientras tanto, ha hecho clic en (x) y borra de su lista ese elemento? Luego, al hacer clic de nuevo, le mostrará los detalles de un elemento eliminado.


Hay 3 formas de pasar datos de padres a hijos

  1. A través del servicio que se puede compartir: debe almacenar en un servicio los datos que desea compartir con los niños
  2. A través de Children Router Resolver si tiene que recibir datos diferentes

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

  3. A través de Parent Router Resolver si tiene que recibir los mismos datos de padre

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

Nota 1: Puedes leer sobre resolver here . También hay un ejemplo de resolución y cómo registrar la resolución en el módulo y luego recuperar los datos de la resolución en el componente. El registro de resolución es el mismo en el padre y el hijo.

Nota 2: Puede leer sobre ActivatedRoute here para poder obtener datos del enrutador


La única forma es usar un servicio compartido.

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 simplemente inválido El componente agregado por el enrutador se agrega como hermano a <router-outlet> y no lo reemplaza.

Ver también https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

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

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


La respuesta de Günters es excelente, solo quiero señalar otra forma sin usar Observables.

Aquí, sin embargo, debemos recordar que estos objetos se pasan por referencia, por lo que si desea realizar un trabajo en el objeto en el elemento secundario y no afectar el objeto principal, sugeriría utilizar la solución de Günther. Pero si no importa, o si realmente es el comportamiento deseado , sugeriría lo siguiente.

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

En su padre puede asignar el valor:

@Injectable() export class SharedService { sharedNode = { // properties }; }

Y en sus hijos (AND padre), inyecte el Servicio compartido en su constructor. Recuerde proporcionar el servicio en la matriz de proveedores a nivel de módulo si desea un servicio singleton en todos los componentes de ese módulo. Alternativamente, solo agregue el servicio en la matriz de proveedores solo en el padre, luego el padre y el niño compartirán la misma instancia de servicio.

this.sharedService.sharedNode = this.node;

Y como Newman señaló amablemente, también puede tener this.sharedService.sharedNode en la plantilla html o un getter:

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