Angular2 コンポーネントで @Input と双方向バインディングを理解する
Angular2 コンポーネントにおける @Input と双方向バインディング
@Input とは?
@Input デコレータは、親コンポーネントから子コンポーネントへ値を渡すためのものです。 子コンポーネントは、@Input でデコレートされたプロパティを使用して、親コンポーネントから受け取った値にアクセスできます。
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<app-child [name]="name"></app-child>
`
})
export class ParentComponent {
name = 'Angular2';
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>こんにちは、{{ name }}さん!</p>
`
})
export class ChildComponent {
@Input() name: string;
}
上記の例では、ParentComponent
は name
というプロパティを ChildComponent
に渡しています。 ChildComponent
は @Input
でデコレートされた name
プロパティを使用して、この値にアクセスし、テンプレートに表示しています。
双方向バインディングとは?
双方向バインディングは、コンポーネント間でデータを同期させる仕組みです。 つまり、一方のコンポーネントで値を変更すると、もう一方のコンポーネントも自動的に更新されます。
Angular2 では、ngModel ディレクティブを使用して双方向バインディングを実現できます。
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<input type="text" [(ngModel)]="name">
<app-child [name]="name"></app-child>
`
})
export class ParentComponent {
name = 'Angular2';
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>こんにちは、{{ name }}さん!</p>
`
})
export class ChildComponent {
@Input() name: string;
}
上記の例では、ngModel
ディレクティブを使用して、入力フィールドの値と name
プロパティをバインドしています。 つまり、ユーザーが入力フィールドに入力した値は、自動的に name
プロパティに反映され、ChildComponent
のテンプレートにも表示されます。 同様に、ChildComponent
で name
プロパティを変更すると、入力フィールドの値も自動的に更新されます。
@Input と 双方向バインディング は、Angular2 コンポーネント間でデータを共有するための強力なツールです。 これらの概念を理解することで、コンポーネントを効率的に設計し、アプリケーション全体のコードをより簡潔に保つことができます。
- 代替手段として、イベントバインディングを使用してコンポーネント間でデータをやり取りすることもできます。
- 双方向バインディングは、パフォーマンス上の問題を引き起こす可能性があるため、注意して使用する必要があります。
- 上記の例はあくまで基本的なものであり、より複雑な双方向バインディングのシナリオも存在します。
<!DOCTYPE html>
<html>
<head>
<title>Angular 2 Sample</title>
<script src="https://unpkg.com/@angular/core@latest/bundles/core.umd.min.js"></script>
<script src="https://unpkg.com/@angular/compiler@latest/bundles/compiler.umd.min.js"></script>
<script src="https://unpkg.com/@angular/platform-browser-dynamic@latest/bundles/platform-browser-dynamic.umd.min.js"></script>
<script src="app.component.ts"></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h1>Angular 2 Sample</h1>
<p>名前:<input type="text" [(ngModel)]="name"></p>
<p>こんにちは、{{ name }}さん!</p>
<app-child [name]="name"></app-child>
`
})
export class AppComponent {
name = 'Angular2';
}
<p>子コンポーネントです。</p>
<p>名前:{{ name }}</p>
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<p>子コンポーネントです。</p>
<p>名前:{{ name }}</p>
`
})
export class ChildComponent {
@Input() name: string;
}
説明
- このテンプレートは、
AppComponent
コンポーネントのルート要素です。 <h1>
タグを使用して、アプリケーションのタイトルを表示します。<input type="text">
タグを使用して、ユーザーが入力できる名前フィールドを作成します。[(ngModel)]="name"
ディレクティブを使用して、入力フィールドの値とname
プロパティを双方向バインディングします。<p>
タグを使用して、name
プロパティの値を挨拶文として表示します。<app-child>
タグを使用して、ChildComponent
コンポーネントを呼び出し、name
プロパティを渡します。
- このテンプレートは、
- このファイルは、
AppComponent
コンポーネントのクラスを定義します。 @Component
デコレータを使用して、コンポーネントのメタデータを指定します。selector
プロパティは、このコンポーネントをどのように使用できるかを定義します。template
プロパティは、このコンポーネントの HTML テンプレートを定義します。name
プロパティは、コンポーネント内で使用する文字列変数です。
- このファイルは、
- 名前フィールドにテキストを入力すると、そのテキスト
- ブラウザに "Angular 2 Sample" というタイトルのページが表示されます。
サービスは、コンポーネント間で共有できるデータとロジックを格納するクラスです。 コンポーネントは、依存関係インジェクションを使用してサービスを注入し、そのサービスのメソッドやプロパティにアクセスできます。
// サービス
@Injectable()
export class DataService {
private data = [];
getData() {
return this.data;
}
setData(newData: any[]) {
this.data = newData;
}
}
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<button (click)="onClick()">データを取得</button>
<app-child [data]="data"></app-child>
`
})
export class ParentComponent {
data: any[];
constructor(private dataService: DataService) {
this.data = dataService.getData();
}
onClick() {
this.data = ['新しいデータ1', '新しいデータ2'];
}
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<ul>
<li *ngFor="let item of data">{{ item }}</li>
</ul>
`
})
export class ChildComponent {
@Input() data: any[];
}
イベント
イベントは、コンポーネント間でデータをやり取りするためのもう 1 つの方法です。 コンポーネントは、イベントを発行し、他のコンポーネントがそのイベントをリッスンして処理することができます。
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<button (click)="onClick()">データを送信</button>
`
})
export class ParentComponent {
onClick() {
this.dataChanged.emit('新しいデータ');
}
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>親コンポーネントから受け取ったデータ:{{ receivedData }}</p>
`
})
export class ChildComponent {
receivedData: string;
constructor() {
this.dataChanged = new EventEmitter<string>();
}
@Input() dataChanged: EventEmitter<string>;
ngOnInit() {
this.dataChanged.subscribe((data) => {
this.receivedData = data;
});
}
}
ルーター
ルーターは、コンポーネント間をナビゲートするために使用されます。 ルーターを使用して、コンポーネントにデータを渡すこともできます。
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<a [routerLink]="['/child', { data: { message: 'こんにちは!' } }]">子コンポーネントへ</a>
`
})
export class ParentComponent {
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>親コンポーネントから受け取ったメッセージ:{{ message }}</p>
`
})
export class ChildComponent {
message: string;
constructor(private activatedRoute: ActivatedRoute) {
this.message = activatedRoute.snapshot.data['message'];
}
}
RxJS
RxJS は、非同期データストリームを処理するためのライブラリです。 RxJS を使用して、コンポーネント間でデータを共有することもできます。
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<button (click)="onClick()">データを送信</button>
`
})
export class ParentComponent {
onClick() {
this.dataService.data$.next('新しいデータ');
}
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>親コンポーネントから受け取ったデータ:{{ data$ | async }}</p>
`
})
export class ChildComponent {
data$: Observable<string>;
angular typescript data-binding