子供はAngular2で親イベントをリッスンします


82

Angularドキュメントには、親からの子イベントのリッスンに関するトピックがあります。それはいいです。しかし、私の目的は何か逆です!。私のアプリには、管理ページのレイアウトビュー(サイドバーメニュー、タスクバー、ステータスなど)を保持する「admin.component」があります。この親コンポーネントでは、管理者の他のページ間でメインビューを変更するようにルーターシステムを構成しました。問題は、変更後に保存することです。ユーザーはタスクバー(admin.componentに配置されている)の保存ボタンをクリックし、子コンポーネントは保存スタッフを実行するためにそのクリックイベントをリッスンする必要があります。


2
これを行うためのベストプラクティスは、サービスと監視可能なイベントのディスパッチを使用することのように思えます。
zpul 2016年

あなたの質問は、この1からあまりにも非類似ではありません。stackoverflow.com/questions/35560860/...
freethebees

@freethebees解決策は同じかもしれませんが、問題の形は異なり、私の意図はこの状況への最善のアプローチを見つけることです。
Hamed Hamedi 2016年

子コンポーネントに渡される単一のイベントのサービスをセットアップするつもりはありません。
TR3B

回答:


101

このドキュメントはあなたに役立つと思います:

実際、親が子に提供する観察可能な/主題を活用することができます。そんな感じ:

@Component({
  (...)
  template: `
    <child [parentSubject]="parentSubject"></child>
  `,
  directives: [ ChildComponent ]
})
export class ParentComponent {
  parentSubject:Subject<any> = new Subject();

  notifyChildren() {
    this.parentSubject.next('some value');
  }
}

子コンポーネントは、次のテーマでサブスクライブできます。

@Component({
  (...)
})
export class ChildComponent {
  @Input()
  parentSubject:Subject<any>;

  ngOnInit() {
    this.parentSubject.subscribe(event => {
      // called when the notifyChildren method is
      // called in the parent component
    });
  }

  ngOnDestroy() {
    // needed if child gets re-created (eg on some model changes)
    // note that subsequent subscriptions on the same subject will fail
    // so the parent has to re-create parentSubject on changes
    this.parentSubject.unsubscribe();
  }

}

そうでなければ、同様の方法でそのような主題を含む共有サービスを活用することができます...


親コンポーネントがngInit内から次の値をブロードキャストしない限り、子コンポーネントのコールバックは実行されません。なぜそうなのですか?
cjsimon 2017

5
ViewChildよりもこのメソッドを使用する利点はありますか?
sunyiitkgp 2017

よりプロフェッショナルに見えますが、私の状況で実験するために数時間を与えた後、子要素を追加/削除する(したがってトピックからサブスクライブを解除する)ときにUnsubscribeErrorsの問題から抜け出すことができませんでした。そこで、TimeBoxingを使用して、@ StephenPaulのはるかに簡単な答えを探しました。とにかく答えてくれてありがとう、そしておそらく私はそれを完全に理解し、それを完璧に動作させるためにあなたの例に正しい(余分な)調整をするのに十分なだけ今rxjsライブラリを取得していません。
ベルヌーイIT

116

後世のために、これに対するより一般的な解決策について言及たいと思いました。ViewChildへの参照を取得し、そのメソッドの1つを直接呼び出すだけです。

@Component({
  selector: 'app-child'
})
export class ChildComponent {

  notifyMe() {
    console.log('Event Fired');
  }
}

@Component({
  selector: 'app-parent',
  template: `<app-child #child></app-child>`
})
export class ParentComponent {

  @ViewChild('child')
  private child: ChildComponent;

  ngOnInit() {
    this.child.notifyMe();
  }
}

3
それは、すぐに私は親コンポーネントを入力するとクラッシュし... Cannot read property 'notifyMe' of undefined
親切なユーザー

1
@ThierryTemplierのなんとなくよりプロフェッショナルな感じのソリューションと比較して、この非常に単純なソリューションに行きました(そこでの私のコメントを参照してください)。
ベルヌーイIT

2
@BernoulliITあなたは良い点を作ります。結局のところ、彼らはほぼ同じことを成し遂げていると思います。私のソリューションはより少ないコードを使用します。彼の解決策は、親コンポーネントがメッセージを送信するために子コンポーネントを挿入する必要がないことを意味します。RXJSは素晴らしいですが、Angularプロジェクト内でRXJSを使いすぎることがよくあります。人々はそれがこの「銀の弾丸」か何かだと思います。実際には、必要以上に複雑になる可能性があります。彼のngOnDestroy()方法の中の彼のコメントを見てください。私の知る限り、それはあまりにも曖昧です。それは私見で起こるのを待っている単なるバグです。
スティーブンポール

1
「彼のngOnDestroy()メソッド内の彼のコメントを見てください。」それがまさに私がそのアプローチを試みたときに「苦しんでいた」ことだと思います、そして私は行き詰まり、それ以上調査する時間があまりありませんでした(私が取り組んでいる商業プロジェクトのために)。それは私の専門家の心を少し「傷つけた」が;)
ベルヌーイIT

1
@StephenPaulに感謝します。私にとって、Parent Calls a Viewchildメソッドは良かったのですが、あなたの答えは私の運命にたどり着くのに役立ちました。
MKJ 2018年

14

私が質問を正しく理解していれば、ここではもっと骨の折れるアプローチが可能かもしれません。仮定-

  • OPの親コンポーネントには保存ボタンがあります
  • 保存する必要のあるデータは子コンポーネントにあります
  • 子コンポーネントが必要とする可能性のある他のすべてのデータには、サービスからアクセスできます

親コンポーネント内

<button type="button" (click)="prop1=!prop1">Save Button</button>
<app-child-component [setProp]='prop1'></app-child-component>

そして子供に..

prop1:boolean;
  @Input()
  set setProp(p: boolean) {
    // -- perform save function here
}

これは、ボタンのクリックを子コンポーネントに送信するだけです。そこから、子コンポーネントはデータを個別に保存できます。

編集:親テンプレートからのデータもボタンクリックと一緒に渡す必要がある場合、それはこのアプローチでも可能です。その場合はお知らせください。コードサンプルを更新します。


0

取得している人のために Cannot read property 'notifyMe' of undefined

ngAfterViewInit()代わりにメソッドを呼び出してみてくださいngOnInit()

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.