web-dev-qa-db-ja.com

「ルーターコンセント」子コンポーネントへのデータの受け渡し(角度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);
                }
            );
    }

そして(いくつかのうちの一つの)私の子供のディスプレイに

export class ChildDisplay implements OnInit{

    @Input()
    node: Node;

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

}

私はルータのアウトレットにデータを注入することしかできないと思っているようには見えません。 Webコンソールでエラーが発生したようです。

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

これは多少理にかなっていますが、次のようにします。

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

ルーターコンセントが同じように動作するようには見えません。

70
Zack

唯一の方法は共有サービスを使うことです。

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

ただ無効です。ルーターによって追加されたコンポーネントは<router-outlet>の兄弟として追加され、それを置き換えません。

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

Güntersの答えは素晴らしいです、私はちょうどObservablesを使わずに別の方法を指摘したいと思います。

ここでも、これらのオブジェクトは参照渡しであることを覚えておく必要があります。そのため、親オブジェクトに影響を与えずに子のオブジェクトに対して何らかの作業を行いたい場合は、Güntherのソリューションを使用することをお勧めします。しかし、それが問題ではない、または実際には望ましい動作の場合、以下のことを提案します。

@Injectable()
export class SharedService {

    sharedNode = {
      // properties
    };
}

あなたの親であなたは値を割り当てることができます:

this.sharedService.sharedNode = this.node;

そしてあなたの子供(そして親)の中で、あなたのコンストラクタの中に共有サービスを注入します。そのモジュールのすべてのコンポーネントに対してシングルトンサービスが必要な場合は、モジュールレベルのプロバイダ配列でサービスを提供することを忘れないでください。あるいは、親のonlyのプロバイダ配列にサービスを追加するだけで、親と子は同じサービスインスタンスを共有します。

node: Node;

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

そして、newmanが親切に指摘したように、htmlテンプレートまたはゲッターにthis.sharedService.sharedNodeを含めることもできます。

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

サービス:

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

成分:

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

親から子にデータを渡す方法は3つあります。

  1. 共有サービスを介して:あなたはあなたが子供と共有したいデータをサービスに保存する必要があります
  2. 異なるデータを受信する必要がある場合は、Children Router Resolverを使用してください。

    this.data = this.route.snaphsot.data['dataFromResolver'];
    
  3. 親から同じデータを受信する必要がある場合は、親ルーターリゾルバを通じて

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

注1:リゾルバについて読むことができます ここ 。リゾルバの例、およびリゾルバをモジュールに登録してからリゾルバからコンポーネントにデータを取得する方法もあります。リゾルバの登録は、親と子で同じです。

注2:ActivatedRouteこちら について読むことができます。

3
Rzv Razvan

this の質問に従い、Angular 7.2では、履歴状態を使用して親から子にデータを渡すことができます。だから、あなたはのようなことをすることができます

送る:

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

取得:

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

しかし、一貫性を保つように注意してください。たとえば、ルータアウトレットを使用して、左側のサイドバーにリストを表示し、右側に選択した項目の詳細を表示するとします。何かのようなもの:


項目1(x)| ..........................................

項目2(x)| ......選択した商品の詳細.......

項目3(x)| ..........................................

項目4(x)| ..........................................


今、あなたはすでにいくつかのアイテムをクリックしたとします。ブラウザの戻るボタンをクリックすると、前の項目の詳細が表示されます。しかし、その間に(x)をクリックして、そのアイテムをリストから削除したとしたらどうでしょうか。その後、バッククリックを実行すると、削除したアイテムの詳細が表示されます。

0
MTZ