![]()
Angularサービス入力:InputとOutputの違いと使い方
概要
この記事では、AngularにおけるInputとOutputの仕組み、ならびにInjectableサービスの役割について詳しく解説します。これにより、Angularアプリケーションのデータ通信とコンポーネント間のやり取りを理解しやすくします。
InputとOutputの基礎知識
Inputプロパティは親コンポーネントから子コンポーネントへのデータの受け渡しを行う方法です。一方、Outputプロパティは子コンポーネントから親コンポーネントへのイベントの発火手段として機能します。
| プロパティ | 説明 |
|---|---|
| Input | 親から子へのデータ受け渡し |
| Output | 子から親へのイベント通知 |
Injectableサービスの概要
Injectableサービスは、依存性注入を通じてアプリケーション全体で共有可能なデータや機能を提供します。これにより、コンポーネント間の通信が効率化され、コードの再利用性が向上します。
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataService {
private messageSource = new BehaviorSubject('初期メッセージ');
currentMessage = this.messageSource.asObservable();
changeMessage(message: string) {
this.messageSource.next(message);
}
}
InputとOutputの利用シーン
InputとOutputはコンポーネント間の直接的な通信に優れていますが、大規模なアプリケーションではInjectableサービスを使用することで、より柔軟なデータフローを実現することができます。
以下は、InputとOutputを使用したコンポーネントの例です。
@Component({
selector: '親コンポーネント',
template: `
<子コンポーネント [data]="parentData" (notify)="onNotify($event)"></子コンポーネント>
`
})
export class ParentComponent {
parentData = '親からのデータ';
onNotify(event: string) {
console.log('子からの通知:', event);
}
}
@Component({
selector: '子コンポーネント',
template: `<button>通知を送る</button>`
})
export class ChildComponent {
@Input() data: string;
@Output() notify = new EventEmitter();
sendNotify() {
this.notify.emit('子が親に送ったメッセージ');
}
}
このように、AngularのInputとOutputを使用することで、コンポーネント間の情報交換が簡単に行え、動的なアプリケーションの構築が可能になります。
受け渡し方法
Angularでコンポーネント間で値を受け渡すための一般的な方法には、以下のものがあります。
- Input, Output を使う
- Service を使う
- RxJS を使う
- URL に付与する
Input, Output を使う
Input, Output は、親子コンポーネント間で値を受け渡すために使用されます。親コンポーネントから子コンポーネントに値を渡すには Input を、子コンポーネントから親コンポーネントに値を渡すには Output を使用します。
例:親コンポーネントから子コンポーネントへの値の受け渡し
親コンポーネント (parent.component.ts)
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<app-child
[control]="myControl"
[placeholder]="myPlaceholder"
[labelText]="myLabel">
</app-child>
`
})
export class ParentComponent {
myControl = '初期値';
myPlaceholder = 'プレースホルダー';
myLabel = 'ラベル';
}
子コンポーネント (child.component.ts)
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<label>{{ labelText }}</label>
<input type="text" [value]="control" [placeholder]="placeholder" />
`
})
export class ChildComponent {
@Input() control: string;
@Input() placeholder: string;
@Input() labelText: string;
}
実行結果
親コンポーネントで定義した値を、子コンポーネントの Input プロパティにバインドすることで、子コンポーネントでその値を使用することができます。
例:子コンポーネントから親コンポーネントへの値の受け渡し
親コンポーネント (parent.component.ts)
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<app-child (message)="onMessage($event)"></app-child>
<p>子コンポーネントからのメッセージ: {{ childMessage }}</p>
`
})
export class ParentComponent {
childMessage: string;
onMessage(message: string) {
this.childMessage = message;
}
}
子コンポーネント (child.component.ts)
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<input type="text" #messageInput (keyup)="sendMessage(messageInput.value)" />
`
})
export class ChildComponent {
@Output() message = new EventEmitter<string>();
sendMessage(message: string) {
this.message.emit(message);
}
}
実行結果
子コンポーネントでは、EventEmitter を使用してイベントを発行し、親コンポーネントではそのイベントを購読することで、子コンポーネントから値を受け取ることができます。
Service を使う
Service を使用すると、親子関係にないコンポーネント間でも値を受け渡すことができます。Service は、コンポーネント間で共有されるデータやロジックを保持するために使用されます。
参考資料
例
サービス (message.service.ts)
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class MessageService {
private message: string;
setMessege(message: string) {
this.message = message;
}
getMessege(): string {
return this.message;
}
}
親コンポーネント (parent.component.ts)
import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'app-parent',
template: `
<button (click)="sendMessage()">子コンポーネントにメッセージを送信</button>
`
})
export class ParentComponent {
constructor(private messageService: MessageService) { }
sendMessage() {
this.messageService.setMessege('親コンポーネントからのメッセージです。');
}
}
子コンポーネント (child.component.ts)
import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'app-child',
template: `
<button (click)="showMessage()">メッセージを表示</button>
<p>{{ message }}</p>
`
})
export class ChildComponent {
message: string;
constructor(private messageService: MessageService) { }
showMessage() {
this.message = this.messageService.getMessege();
}
}
実行結果
親コンポーネントと子コンポーネントは、どちらも同じ MessageService を注入することで、サービスを介して値を共有することができます。
RxJS を使う
RxJS は、リアクティブプログラミングを実現するためのライブラリです。RxJS を使用すると、値の変化を監視し、それに応じて処理を実行することができます。コンポーネント間で値をリアルタイムに受け渡したい場合に便利です。
参考資料
例
サービス (data.service.ts)
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataService {
private dataSubject = new Subject<string>();
sendData(data: string) {
this.dataSubject.next(data);
}
getData(): Observable<string> {
return this.dataSubject.asObservable();
}
}
親コンポーネント (parent.component.ts)
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-parent',
template: `
<input type="text" #dataInput (keyup)="sendData(dataInput.value)" />
`
})
export class ParentComponent {
constructor(private dataService: DataService) { }
sendData(data: string) {
this.dataService.sendData(data);
}
}
子コンポーネント (child.component.ts)
import { Component, OnDestroy } from '@angular/core';
import { DataService } from './data.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-child',
template: `
<p>親コンポーネントからのデータ: {{ data }}</p>
`
})
export class ChildComponent implements OnDestroy {
data: string;
subscription: Subscription;
constructor(private dataService: DataService) {
this.subscription = this.dataService.getData().subscribe(data => {
this.data = data;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
実行結果
親コンポーネントでは、入力値が変更されるたびに DataService の sendData メソッドを呼び出してデータを送信します。子コンポーネントでは、DataService の getData メソッドから Observable を取得し、購読することで、データの変更をリアルタイムに受け取ることができます。
URL に付与する
URL にパラメータを付与することで、コンポーネントに値を渡すことができます。これは、例えば、ユーザーの詳細情報ページなど、URL に基づいて異なるコンテンツを表示したい場合に便利です。
参考資料
例
app.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UserComponent } from './user/user.component';
const routes: Routes = [
{ path: 'user/:id', component: UserComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html
<a routerLink="/user/1">ユーザー1</a> | <a routerLink="/user/2">ユーザー2</a> <router-outlet></router-outlet>
サービス (user.service.ts)
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
getUsers() {
return [
{ id: 1, name: '田中太郎' },
{ id: 2, name: '佐藤花子' }
];
}
getUser(id: number) {
return this.getUsers().find(user => user.id === id);
}
}
ユーザー情報コンポーネント (user.component.ts)
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { UserService } from '../user.service';
@Component({
selector: 'app-user',
template: `
<h2>ユーザー情報</h2>
<p>ID: {{ user.id }}</p>
<p>名前: {{ user.name }}</p>
`
})
export class UserComponent implements OnInit {
user: any;
constructor(
private route: ActivatedRoute,
private userService: UserService
) { }
ngOnInit() {
const id = +this.route.snapshot.paramMap.get('id');
this.user = this.userService.getUser(id);
}
}
実行結果
ActivatedRoute を使用することで、URL からパラメータを取得することができます。この例では、ユーザー ID を URL から取得し、UserService を使用してユーザー情報を取得しています。
参考文献
Q&A
Q1: InputとOutputはどのように違いますか?
A1: Inputは親から子へのデータ受け渡しを行い、Outputは子から親へのイベント通知を行います。
Q2: Injectableサービスはどのように利用しますか?
A2: Injectableサービスは依存性注入を通じて、他のコンポーネントやサービスで利用できます。
Q3: InputとOutputの両方を使用する際の最適なパターンは何ですか?
A3: 小規模なコンポーネント間の直接通信にはInputとOutputを使い、大規模なアプリケーションではInjectableサービスを併用するのが最適です。