ViewChildとContentChildはAngularで何でしょうか?
このブログではAngular ViewChild と ContentChild を使用して、コンポーネントのビュー内の子コンポーネントと DOM 要素にアクセスして操作する方法を示します。すべて読む。
ViewChildおよびContentChildはコンポーネント通信にAngularに使用されます。例えば、親Angularコンポーネントが子コンポーネントにアクセスしたい場合は、ViewChildまたはContentChildを使用します。
このブログ記事では、Angular ViewChildとAngular ContentChildの本質を説明し、アプリ内での使い方をご紹介します。
ViewChildとは何かAngular
Angular ViewChildまたはViewChildrenデコレーターは、コンポーネント参照名またはクラス名を使ってテンプレートにクエリを送り出し、コンポーネントインスタンスへの参照を取得するために使用されます。Angularの ViewChildは最初の一致するコンポーネントを返し、ViewChildrenはすべての一致するコンポーネントをQueryListとして返します。これらの参照を使ってコンポーネントクラスやそのDOM要素を扱うことができます。
親コンポーネント内で以下の機能にアクセスしたい場合は、Angularのデコレーター@ViewChild使ってください。
Using MessageComponent
以下のリストに示されているようにMessageComponentがあると仮定しましょう:
import { Component, Input } from "@angular/core";
@Component({
selector: "app-message",
template: `<h2>{{message}}</h2>`,
})
export class MessageComponent {
@Input() message: string;
}
AppComponent内のMessageComponentを使っています。こちらに示されている通りです:
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-root",
template: ` <div>
<h1>Messages</h1>
<app-message [message]="message"></app-message>
</div>`,
})
export class AppComponent implements OnInit {
message: any;
ngOnInit() {
this.message = "Hello World !";
}
}
MessageComponentはAppComponentのテンプレート内に配置されます。したがって、ViewChildとしてアクセスできます。
export class AppComponent implements OnInit, AfterViewInit {
message: any;
@ViewChild(MessageComponent) messageComponent: MessageComponent;
ngAfterViewInit() {
console.log(this.messageComponent);
}
ngOnInit() {
this.message = "Hello World !";
}
}
MessageComponentの値の変更
では、MessageComponentプロパティの値を変更してみます。
ngAfterViewInit() {
console.log(this.messageComponent);
this.messageComponent.message = 'Passed as View Child';
}
ここではViewChildプロパティの値を変更しています。
ViewChildrenとQueryList Angular使う方法
私たちは *ngFor 指令内で MessageComponent を使用しています;したがって、MessageComponentへの複数の参照があります。現在、以下のリストに示すようにViewChildrenおよびQueryListとしてアクセスできます。
@ViewChildren(MessageComponent) messageComponent: QueryList<MessageComponent>;
ngAfterViewInit() {
console.log(this.messageComponent);
}
出力にはViewChildernとしてMessageComponentのさまざまな参照が表示されます。
では、以下のリストに示されているようにViewChildrenのプロパティを更新してみましょう。
ngAfterViewInit() {
console.log(this.messageComponent);
this.messageComponent.forEach((item) => { item.message = 'Infragistics'; });
}
ご覧の通り、私たちはAngular ViewChildrenの各項目を繰り返し、各プロパティを更新しています。これによりプロパティの値は更新されますが、やはり「最後のチェック後に式が変更されました」というエラーが出ます。
手動で変更検出(例えばViewChild)を呼び出すことで修正できます。AfterContentInitのライフサイクルフックにはViewChildren参照は利用できないことをご注意ください。以下の一覧に示されているように、ngAfterContentInit() ライフサイクルフックでUndefined ViewChildren参照が得られます:
ngAfterContentInit() {
console.log(this.messageComponent); // undefined
}
ただし、手動で「変更検出」を呼び出して「最後にチェックされた後に表現が変更されました」というエラーを修正できます
変化検出機構を使用する
- Import ChangeDetectorRef from @angular/core
- コンポーネントクラスのコンストラクタに注入します
- ViewChildプロパティが変更された後にdetectChanges()メソッドを呼び出します
以下のリストにあるような手動の変更検出を使うことができます:
@ViewChildren(MessageComponent) messageComponent: QueryList<MessageComponent>;
constructor(private cdr: ChangeDetectorRef) {
}
ngAfterViewInit() {
console.log(this.messageComponent);
this.messageComponent.forEach((item) => { item.message = 'Infragistics'; });
this.cdr.detectChanges();
}
ContentChildとは何Angular?
Angular ContentChildプロパティデコレーターはViewChildに非常に似ており、コンポーネント内の投影コンテンツと操作する強力な手段を提供します。これを使えば、DOM内のProjected Contentへの参照を簡単に取得できます。
まずはContentChildについて理解しましょう。テンプレート内に存在する任意の要素はContentChildです。
理解するために、MessageContainerComponentを考えてみましょう。
import { Component } from "@angular/core";
@Component({
selector: "app-messagecontainer",
template: ` <div>
<h3>{{greetMessage}}</h3>
<ng-content select="app-message"></ng-content>
</div>`,
})
export class MessageContainerComponent {
greetMessage = "Ignite UI Rocks!";
}
このコンポーネントでは、コンテンツプロジェクションAngularを使用しています。
ContentChild Angular MessageComponentのパッシング
コンテンツ<に投影された任意の要素やコンポーネントは>ContentChildとなります。MessageContainerComponent内に投影されたMessageComponentにアクセスし、通信したい場合は、それをContentChildとして読み取る必要があります。
AngularでContentChildの使い方を学ぶ前に、まずMessageContainerComponentがどのように使われ、MessageComponentがどのように投影されているかを確認しましょう。
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-root",
template: ` <div>
<app-messagecontainer>
<app-message [message]="message"></app-message>
</app-messagecontainer>
</div>`,
})
export class AppComponent implements OnInit {
message: any;
ngOnInit() {
this.message = "Hello World !";
}
}
上記のリストにあるように、AppComponentでMessageContainerComponentを使用し、MessageComponentをその中に投影する形で渡しています。MessageComponentはコンテンツプロジェクションを伴うMessageContainerComponentで使用されるため、ContentChild Angularなります。
MessageComponnetはMessageContainerComponentのテンプレート内で投影され使用されるため、以下のようにContentChildとして使用できます。
import { Component, ContentChild, AfterContentInit } from "@angular/core";
import { MessageComponent } from "./message.component";
@Component({
selector: "app-messagecontainer",
template: ` <div>
<h3>{{greetMessage}}</h3>
<ng-content select="app-message"></ng-content>
</div>`,
})
export class MessageContainerComponent implements AfterContentInit {
greetMessage = "Ignite UI Rocks!";
@ContentChild(MessageComponent) MessageComponentContentChild: MessageComponent;
ngAfterContentInit() {
console.log(this.MessageComponentContentChild);
}
}
以下の作業を行う必要があります。
- @angular/coreからContentChildとAfterContentInitをインポートしてください。
- コンポーネントクラスにAfterContentInitのライフサイクルフックを実装してください。
- デコレーター@ContentChildで物件を作りましょう。
- ngAfterContentInitのライフサイクルフック内でアクセスしてください。
コンポーネントのngAfterContentInitライフサイクルフック内でContentChildプロパティを変更できます。以下のリストに示すように、複数のMessageComponentが投影されていると仮定します。
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-root",
template: ` <div>
<app-messagecontainer>
<app-message *ngFor="let m of messages" [message]="m"></app-message>
</app-messagecontainer>
</div>`,
})
export class AppComponent implements OnInit {
messages: any;
ngOnInit() {
this.messages = this.getMessage();
}
getMessage() {
return ["Hello India", "Which team is winning Super Bowl? ", "Have you checked Ignite UI ?", "Take your broken heart and make it to the art"];
}
}
現在、複数のContentChildが存在するため、以下のリストに示されているようにContentChildrenとしてアクセスする必要があります。
export class MessageContainerComponent implements AfterContentInit {
greetMessage = "Ignite UI Rocks!";
@ContentChildren(MessageComponent) MessageComponentContentChild: QueryList<MessageComponent>;
ngAfterContentInit() {
console.log(this.MessageComponentContentChild);
}
}
ContentChildrenとQueryListの活用
ContentChildrenとQueryListを扱うには、以下の作業を行う必要があります。
- @angular/coreからContentChildren、QueryList、AfterContentInitをインポートします。
- デコレーター@ContentChildrenでQueryList型のプロパティを作成します。
- ngAfterContentInit() ライフサイクルフックでContentChildren参照にアクセスしてください。
ContentChildrenで各アイテムをクエリし、プロパティを次のように変更できます:
ngAfterContentInit() {
this.MessageComponentContentChild.forEach((m) => m.message = 'Foo');
}
これがContentChildrenをAngularで使う方法です。
まとめ
ViewChildとContentChildはAngularの非常に重要な機能です。これらは親コンポーネント内の子コンポーネントへのアクセスを可能にするために使われます。コンポーネントテンプレートに含まれる任意の指令、コンポーネント、要素はViewChildとしてアクセスされます。一方、<ng-content>内に投影された任意の要素やコンポーネントはContentChildとしてアクセスされます。
さらに ViewChild と ContentChild をAngularでシンプルにするために、機能豊富なIgnite UI for Angularコンポーネントライブラリを試してみてください。最速のAngularデータグリッドと60+の高性能チャートを提供し、現代の高性能Angularアプリを簡単に構築できます。
(Last Updated: 08.09.2023)
