Angularでコンポーネント間通信:EventEmitter vs Observable

2024-04-02

Angularにおけるデリゲーション: EventEmitterとObservable

EventEmitterは、コンポーネント間でイベントを伝達するシンプルな方法です。イベント発生時に購読者に通知を送信し、購読者はそのイベントに応じた処理を実行できます。

EventEmitterの利点:

  • 軽量で使いやすい
  • シンプルなイベント伝達に適している
  • コンポーネント間の直接的な結合を促進する
  • 状態管理が煩雑になる
  • イベントの順序制御が難しい *複雑なデータの伝達には不向き

Observableは、データストリームを表現する強力なツールです。データストリームとは、時間経過とともに変化するデータの連続的な流れです。Observableは、データストリームを購読し、データの変化を通知を受け取ることができます。

Observableの利点:

  • データストリームを抽象化し、統一的に扱える
  • 状態管理が容易
  • イベントの順序制御やフィルタリングなどの高度な操作が可能
  • 複雑なデータの伝達に適している
  • EventEmitterよりも複雑で習得に時間がかかる
  • すべてのユースケースに適しているわけではない

EventEmitterとObservableはそれぞれ異なる利点と欠点を持つため、ユースケースに応じて使い分ける必要があります。

  • シンプルなイベント伝達にはEventEmitterが適しています。
  • 複雑なデータの伝達や状態管理が必要な場合はObservableが適しています。

以下は、それぞれのユースケースの例です。

  • ボタンクリックイベント
  • フォーム入力イベント
  • コンポーネント間の単純なデータ共有
  • リアルタイムデータの更新
  • Ajaxリクエスト
  • 非同期処理
  • 状態管理

EventEmitterとObservableは、Angularアプリケーションにおけるコンポーネント間通信の重要なツールです。それぞれの利点と欠点を理解し、ユースケースに応じて使い分けることが重要です。




EventEmitter

import { Component, OnInit, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'my-emitter',
  templateUrl: './emitter.component.html',
})
export class EmitterComponent implements OnInit {

  @Output() buttonClick = new EventEmitter<void>();

  constructor() { }

  ngOnInit() {
  }

  onClick() {
    this.buttonClick.emit();
  }

}

@Component({
  selector: 'my-parent',
  templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  onButtonClick() {
    console.log('Button clicked!');
  }

}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
})
export class AppComponent {

  constructor() { }

  ngOnInit() {
  }

}
<my-parent>
  <my-emitter (buttonClick)="onButtonClick()"></my-emitter>
</my-parent>

parent.component.html

<h1>親コンポーネント</h1>
<button (click)="onButtonClick()">ボタンをクリック</button>
<h1>子コンポーネント</h1>
<button (click)="onClick()">ボタンをクリック</button>

Observable

import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Observable, of } from 'rxjs';

@Component({
  selector: 'my-observable',
  templateUrl: './observable.component.html',
})
export class ObservableComponent implements OnInit {

  @Output() buttonClick = new Observable<void>();

  constructor() { }

  ngOnInit() {
  }

  onClick() {
    this.buttonClick = of(null);
  }

}

@Component({
  selector: 'my-parent',
  templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  onButtonClick() {
    console.log('Button clicked!');
  }

}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
})
export class AppComponent {

  constructor() { }

  ngOnInit() {
  }

}
<my-parent>
  <my-observable (buttonClick)="onButtonClick()"></my-observable>
</my-parent>
<h1>親コンポーネント</h1>
<button (click)="onButtonClick()">ボタンをクリック</button>
<h1>子コンポーネント</h1>
<button (click)="onClick()">ボタンをクリック</button>

上記のサンプルコードは、EventEmitterとObservableを使ったコンポーネント間通信の例です。それぞれのコードを参考に、ユースケースに応じて使い分けてください。




Angularにおけるコンポーネント間通信の他の方法

サービスは、コンポーネント間でデータを共有するために使用できるオブジェクトです。サービスはシングルトンとして登録されるため、アプリケーション全体で同じインスタンスが使用されます。

例:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MyService {

  private data: string;

  constructor() { }

  setData(data: string) {
    this.data = data;
  }

  getData() {
    return this.data;
  }

}
import { Component, OnInit } from '@angular/core';
import { MyService } from './my.service';

@Component({
  selector: 'my-parent',
  templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {

  constructor(private myService: MyService) { }

  ngOnInit() {
    this.myService.setData('Hello World!');
  }

}
import { Component, OnInit } from '@angular/core';
import { MyService } from './my.service';

@Component({
  selector: 'my-child',
  templateUrl: './child.component.html',
})
export class ChildComponent implements OnInit {

  constructor(private myService: MyService) { }

  ngOnInit() {
    const data = this.myService.getData();
    console.log(data); // 'Hello World!'
  }

}

依存関係注入は、コンポーネントにサービスを注入する方法です。コンポーネントクラスのコンストラクタにサービスを指定することで、コンポーネント内でサービスを使用することができます。

import { Component, OnInit, Inject } from '@angular/core';
import { MyService } from './my.service';

@Component({
  selector: 'my-parent',
  templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {

  constructor(
    @Inject(MyService) private myService: MyService,
  ) { }

  ngOnInit() {
    this.myService.setData('Hello World!');
  }

}
import { Component, OnInit, Inject } from '@angular/core';
import { MyService } from './my.service';

@Component({
  selector: 'my-child',
  templateUrl: './child.component.html',
})
export class ChildComponent implements OnInit {

  constructor(
    @Inject(MyService) private myService: MyService,
  ) { }

  ngOnInit() {
    const data = this.myService.getData();
    console.log(data); // 'Hello World!'
  }

}

ルーティングは、異なるコンポーネント間をナビゲートするために使用できます。URLに基づいてコンポーネントを表示したり、コンポーネント間でデータを渡したりすることができます。

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'my-parent',
  templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit() {
    this.router.navigate(['/child', { data: 'Hello World!' }]);
  }

}

import { Component, OnInit, ActivatedRoute } from '@angular/core';

@Component({
  selector: 'my-child',
  templateUrl: './child.component.html',
})
export class ChildComponent implements OnInit {

  constructor(private activatedRoute: ActivatedRoute) { }

  ngOnInit() {
    const data = this.activatedRoute.snapshot.data['data'];
    console.log(data); // 'Hello World!'
  }

}

状態管理ライブラリ

NgRx Storeなどの状態管理ライブラリを使用して、コンポーネント間でデータを共有することができます。

import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/

angular observer-pattern observable


Angular 2 で条件付き処理をマスター! Ternary Operator、カスタムディレクティブ、RxJS を駆使したテクニック

以下の例は、gender プロパティに基づいてユーザーの名前を表示するパイプの例です。この例では、以下のパイプを使用しています。titleCase: 名前を大文字に変換します。genderedName: 性別に基づいて接尾辞を追加します。genderedName パイプはカスタムパイプであり、以下のロジックを実装しています。...


TypeScript で実現する Angular Reactive Forms:FormGroup と FormArray でスマートに要素を削除

Angular Reactive Forms の FormGroup と FormArray は、動的なフォームを作成するための強力なツールです。 FormArray は、フォーム内に可変個数の要素オブジェクトを含めることができる特別なタイプの FormGroup です。 このチュートリアルでは、TypeScript を使用して FormGroup と FormArray から特定の要素オブジェクトを値に基づいて削除する方法を説明します。...


Angular 5 + TypeScript でレスポンス ヘッダーを解析する

API レスポンス ヘッダーには、ステータス コード、キャッシュ コントロール情報、認証トークンなど、API 応答に関する重要な情報が含まれています。これらのヘッダーにアクセスすることで、アプリケーションのロジックを強化し、エラーをデバッグすることができます。...


【保存版】Angular Materialで空データ時の「データが見つかりませんでした」メッセージの表示方法3選

*ngIf ディレクティブは、条件に応じて要素を表示したり非表示にしたりするのに使用できます。この場合、dataSource. data プロパティが空かどうかをチェックして、空メッセージを表示できます。ngNoData ディレクティブを使用する...


Angularで発生する「Configuration is not set in the workspace」エラー:原因と解決策を徹底解説

"Angular - Configuration is not set in the workspace" というエラーは、Angular CLIを使用してプロジェクトをビルドまたは実行しようとすると発生することがあります。これは、ワークスペース構成ファイル (angular...


SQL SQL SQL SQL Amazon で見る



Angular 2 サービスで Observable を返すベストプラクティス

Angular 2 の基礎知識RxJS の基礎知識Observable は、非同期データストリームを表すオブジェクトです。Angular 2 サービスでは、Observable を使用して、サーバーからのデータ取得、イベントの処理、その他の非同期操作を実行できます。


Angular上級者向け:グローバルイベントを使いこなすためのテクニック

グローバルイベントは、以下の2つの方法で発生させることができます。EventEmitter サービスは、イベントを発生させ、購読するための機能を提供します。このサービスを利用するには、以下の手順が必要です。イベントを発生させるコンポーネントで、EventEmitter サービスをインポートします。


Angular 2 でサービス、NgRedux/Store、EventBus を使用する方法

Angular 2 では、ルートスコープは廃止され、以下の3つの方法でコンポーネント間でデータを共有することができます。コンポーネントのメンバー変数と @Input プロパティコンポーネントのメンバー変数は、そのコンポーネント内でのみアクセス可能なスコープ変数です。一方、@Input プロパティは、他のコンポーネントから値を受け取るために使用されます。


RxJS の Subject を使って Angular サービスでデータやイベントを伝達する方法

EventEmitter の概要コンポーネント間でデータやイベントを伝達するためのクラステンプレート内でイベントバインディングを使って購読サービス内で使用可能サービスでの EventEmitter の使い方誤った使い方上記のように、サービス内で EventEmitter を直接インスタンス化して使用することは 誤り です。


Angular 2以降とTypescriptにおけるグローバル変数の宣言方法:各方法の特徴比較

最もシンプルで手軽な方法は、windowオブジェクトにプロパティを追加する方法です。利点:記述が簡単コード量が少なく済むグローバルスコープを汚染してしまう名前空間の衝突が発生する可能性があるテストコードでモック化しにくいサービスを利用することで、グローバル変数をカプセル化し、名前空間の衝突を防ぐことができます。


Angular 2 でコンポーネント間のデータ共有: Event Emitters と Subject の比較

Event Emitters は、コンポーネント間の親子関係でイベントを伝達するために使用されます。一方、Subject は、より複雑なイベント伝達やデータ共有に利用できます。Event Emitters は、Angular のコア機能であり、以下の特徴があります。


Subjectやngrx/storeを使って親コンポーネントから子コンポーネントへイベントを発行する方法

EventEmitterは、コンポーネント間でイベントを発行・受信するための便利な機能です。以下の手順で実装できます。子コンポーネントでイベントを定義ポイント@Output デコレータを使って、子コンポーネントでイベントプロパティを定義します。