必ず覚えておきたい! Angular2でコンポーネントの子要素を参照する方法

必ず覚えておきたい! Angular2でコンポーネントの子要素を参照する方法

Angular2でアプリケーションを構築する時に、
親コンポーネントから子コンポーネントを操作したいことが多くあります。
例えば、子コンポーネントの値を取得・変更したい時や、DOMを取得したい時などが挙げられます。

Angular2では、ViewChildrenContentChildren を使用することで、
親要素から子要素を参照することができます。

今回はViewChildrenContentChildren を使用した、子要素の参照方法を紹介します。

ViewChildren とは

コンポーネントのテンプレートの中に配置された子要素をViewChildren と呼びます。

使い方は、@ViewChildren もしくは @ViewChild デコレータを @angular/core からインポートして使用します。
@ViewChildren は複数個取得でき、@ViewChild は1つだけ取得するという違いがあります。

次のコードでは、@ViewChildren を使用して子要素を参照しています。

parent.ts

import { Component, ViewChildren } from '@angular/core'
import { ChildComponent } from './child';

@Component({
selector: 'my-parent',
providers: [],
template: `
<div>children count: <strong>{% raw %}{{{% endraw %} count {% raw %}}}{% endraw %}</strong></div>
<div>
<ol><my-child ngfor="let log of logs" log=""></my-child></ol>
</div>
`
})
export class ParentComponent implements AfterViewInit {

logs = [ 'foo', 'bar', 'baz' ];
count = 0;

@ViewChildren(ChildComponent) children: QueryList<childcomponent>;</childcomponent>

// 子コンポーネントの初期化後に実行
ngAfterViewInit() {
this.count = this.children.length;
}

}

次のコードがデコレータの使用部分です。

@ViewChildren(ChildComponent) children: QueryList<childcomponent>;

@ViewChildren() の引数に、ChildComponent を渡すことで、自身のテンプレート内の ChildComponent を取得するよう指定します。
取得結果としての返り値は QueryList と呼ばれる、配列に似た要素集合で取得するのが一般的です。QueryListは、forEach メソッドでの繰り返し処理や、 length プロパティによる要素数の取得が可能です。

this.count = this.children.length;

[aside type=”normal”]
【公式ドキュメント】 QueryList – angular.io
[/aside]

次のデモでは ChildComponent の数を出力しています。

ContentChildren とは

開始タグと終了タグの間に置かれた要素ContentChildren と呼びます。

使い方はViewChildrenと同じく、@ContentChildren@ContentChild デコレータを @angular/core からインポートして使用します。
@ContentChildren は複数個取得でき、@ContentChild は1つだけ取得するという違いがあります。

次のコードでは、@ContentChildren を使用して子要素を参照しています。

parent.ts

import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core'

// Name
@Component({
selector: 'my-name',
template: `
<ul>
 	<li><ng-content></ng-content></li>
</ul>
`
})
class NameComponent {}

// Child
@Component({
selector: 'my-child',
template: `
<div>children count: <strong>{% raw %}{{{% endraw %} count {% raw %}}}{% endraw %}</strong></div>
<ng-content></ng-content>
`
})
class ChildComponent implements AfterContentInit {

count = 0;
@ContentChildren(NameComponent) children: QueryList<namecomponent>;</namecomponent>

// 子要素の初期化後に実行
ngAfterContentInit() {
this.count = this.children.length;
}
}

// Parent
@Component({
selector: 'my-parent',
template: `
<my-child></my-child>
<ol><my-name ngfor="let name of members">{% raw %}{{{% endraw %} name {% raw %}}}{% endraw %}</my-name></ol>
`
})
export class ParentComponent implements AfterContentInit, AfterViewInit {

members = [ 'のび太', 'スネ夫', 'ジャイアン', '出木杉' ];

}

ParentComponent のテンプレート部分に注目してください。

template: `
<my-child></my-child>
<ol><my-name ngfor="let name of members">{% raw %}{{{% endraw %} name {% raw %}}}{% endraw %}</my-name></ol>
`

ChildComponent の要素の中にolリストが含まれています。
このolリストが ChildComponentContentChild となります。

次のデモでは @ContentChildren を使って ChildComponent の中にある、NameComponent の数を出力しています。

まとめ

今回紹介した内容は、コンポーネント・要素を参照するための基本な知識なので、しっかり抑えておきたいところです。

このViewやContentという考え方は、Lifecycle Hooks でも応用が効き、
Angular2でのアプリケーション構築では欠かすことのできない重要な概念です。
あわせて Lifecycle Hooks の記事を読むとより一層理解が深まるでしょう。

[aside type=”normal”]
【関連記事】 Angular2のLifecycle Hooksを理解する
[/aside]

参考

五十川 洋平(Yohei Isokawa)

五十川 洋平(Yohei Isokawa)

フロントエンドエンジニア/面白法人カヤックなどのWeb制作会社に勤務したのち、故郷の新潟に戻り独立。JSフレームワークAngularやFirebase、Google Cloud Platformを使ったWebアプリ開発が得意。 また、Udemyのプログラミング解説の講師、writer-app.comの自主開発や上越TechMeetupの主催などを行っています。

プロフィール