2017-01-03 12 views
33

Mam element nadrzędny, który trafia do serwera i pobiera obiekt.Przekazywanie danych do komponentów potomnych "router-outlet" (kąt 2)

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

I (jeden z kilku) mój wyświetlacz dziecko

export class ChildDisplay implements OnInit{ 

    @Input() 
    node: Node; 

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

} 

Nie wydaje się jak myślałem mogę po prostu wstrzyknąć dane do routera-gniazdka. Wygląda na to, że pojawia się błąd w konsoli internetowej ...

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

To nieco sens, ale jak bym wykonać następujące czynności ....

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 

to nie wygląda gniazda routerów działają w ten sam sposób.

Odpowiedz

34

Jedynym sposobem jest skorzystanie z usługi wspólnej.

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

jest nieważny. Komponent dodany przez router jest dodawany jako rodzeństwo do <router-outlet> i nie zastępuje go.

Zobacz także https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

@Injectable() 
export class NodeService { 
    private node:Subject<Node> = new BehaviorSubject<Node>(); 
    node$ = this.node.asObservable(); 

    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

Wygląda na to, że zadziała to dla mnie. Wydaje się trochę nieporządny, ale to przerwy. – Zack

+0

Tak, właśnie dodałem inną metodę "announceNewNode" do mojej usługi węzła, która pozwoli komponentom podrzędnym wiedzieć, kiedy nadejdzie czas aktualizacji. Następnie subskrybuję usługę w komponencie potomnym. Dzięki! – Zack

+0

W ostatniej klasie jest "$." literówka? Nie mogę znaleźć żadnego odniesienia do niego ... – Gyromite

22

Gunters odpowiedź jest super, po prostu chcę podkreślić inny sposób bez użycia obserwabli.

Tutaj jednak musimy pamiętać, że te obiekty są przekazywane przez odniesienie, więc jeśli chcesz wykonać pewne prace nad obiektem w elemencie potomnym i nie wpływać na obiekt nadrzędny, sugerowałbym skorzystanie z rozwiązania Günthera. Ale jeśli to nie ma znaczenia, lub faktycznie jest pożądane zachowanie, chciałbym zasugerować następujące.

@Injectable() 
export class SharedService { 

    sharedNode = { 
     // properties 
    }; 
} 

W rodzica można przypisać wartość:

this.sharedService.sharedNode = this.node; 

I w twoich dzieci (i rodziców), wstrzyknąć Shared Service w konstruktorze. Pamiętaj, aby podać usługę na poziomie modułów array array, jeśli chcesz korzystać z usługi singleton na wszystkich komponentach w tym module. Alternatywnie, po prostu dodaj usługę do tablicy providerów w rodzicu tylko, wtedy rodzic i dziecko będą udostępniać tę samą instancję usługi.

node: Node; 

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

I jak Newman uprzejmie wskazał, można również this.sharedService.sharedNode w szablonie html lub getter:

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

Chciałbym dać więcej niż raz zaakceptuj. – Zack

+2

done ........... – Zack

+3

można/powinienem połączyć się bezpośrednio z sharedService.sharedNode w html. W ten sposób aktualizacje w sharedNode będą utrzymywane w synchronizacji. – newman

5

Usługa:

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

Składnik:

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

Proszę podać kod jako tekst, a nie jako obrazek – Rob

+0

To powinna być najlepsza odpowiedź! Bardzo schludne i czyste ponowne użycie. Uratowałeś mojego kumpla dnia. Emitowanie danych i korzystanie z nich to świetny pomysł. – JavaFreak

+2

@JavaFreak and egor: To podejście nie jest zalecane, sprawdź: https://stackoverflow.com/a/36076701/6294072 jeśli chcesz iść w ten sposób, użyj Tematu lub BehaviorSubject zamiast, tak jak Günter przedstawiony. – Alex

Powiązane problemy