必ず覚えておきたい! 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: </span>
    <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">children</span> <span class="na">count</span><span class="p">:</span> <span class="o"><</span><span class="nx">strong</span><span class="o">></span><span class="p">{{</span> <span class="nx">count</span> <span class="p">}}</span><span class="o"><</span><span class="sr">/strong></</span><span class="nx">div</span><span class="o">></span>
    <span class="o"><</span><span class="nx">div</span><span class="o">></span>
      <span class="o"><</span><span class="nx">ol</span><span class="o">></span>
        <span class="o"><</span><span class="nx">my</span><span class="o">-</span><span class="nx">child</span> <span class="o">*</span><span class="nx">ngFor</span><span class="o">=</span><span class="s2">"let log of logs"</span> <span class="p">[</span><span class="nx">log</span><span class="p">]</span><span class="o">=</span><span class="s2">"log"</span><span class="o">><</span><span class="sr">/my-child</span><span class="err">>
</span>      <span class="o"><</span><span class="sr">/ol</span><span class="err">>
</span>    <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span>  <span class="err">,
  directives: [
    ChildComponent
  ]
})
export class ParentComponent implements AfterViewInit {

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

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

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

}

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

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

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

this.count = this.children.length;

デモでは 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: </span><span class="o"><</span><span class="nx">li</span><span class="o">><</span><span class="nx">ng</span><span class="o">-</span><span class="nx">content</span><span class="o">><</span><span class="sr">/ng-content></</span><span class="nx">li</span><span class="o">></span><span class="err">
})
class NameComponent {}

// Child
@Component({
  selector: 'my-child',
  template: </span>
    <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">children</span> <span class="na">count</span><span class="p">:</span> <span class="o"><</span><span class="nx">strong</span><span class="o">></span><span class="p">{{</span> <span class="nx">count</span> <span class="p">}}</span><span class="o"><</span><span class="sr">/strong></</span><span class="nx">div</span><span class="o">></span>
    <span class="o"><</span><span class="nx">ng</span><span class="o">-</span><span class="nx">content</span><span class="o">><</span><span class="sr">/ng-content</span><span class="err">>
</span>  <span class="err">
})
class ChildComponent implements AfterContentInit {

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

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

// Parent
@Component({
  selector: 'my-parent',
  template: </span>
    <span class="o"><</span><span class="nx">my</span><span class="o">-</span><span class="nx">child</span><span class="o">></span>
      <span class="o"><</span><span class="nx">ol</span><span class="o">></span>
        <span class="o"><</span><span class="nx">my</span><span class="o">-</span><span class="nx">name</span> <span class="o">*</span><span class="nx">ngFor</span><span class="o">=</span><span class="s2">"let name of members"</span><span class="o">></span><span class="p">{{</span> <span class="nx">name</span> <span class="p">}}</span><span class="o"><</span><span class="sr">/my-name</span><span class="err">>
</span>      <span class="o"><</span><span class="sr">/ol</span><span class="err">>
</span>    <span class="o"><</span><span class="sr">/my-child</span><span class="err">>
</span>  <span class="err">,
  directives: [
    ChildComponent,
    NameComponent
  ]
})
export class ParentComponent implements AfterContentInit, AfterViewInit {

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

}

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

template: </span>
  <span class="o"><</span><span class="nx">my</span><span class="o">-</span><span class="nx">child</span><span class="o">></span>
    <span class="o"><</span><span class="nx">ol</span><span class="o">></span>
      <span class="o"><</span><span class="nx">my</span><span class="o">-</span><span class="nx">name</span> <span class="o">*</span><span class="nx">ngFor</span><span class="o">=</span><span class="s2">"let name of members"</span><span class="o">></span><span class="p">{{</span> <span class="nx">name</span> <span class="p">}}</span><span class="o"><</span><span class="sr">/my-name</span><span class="err">>
</span>    <span class="o"><</span><span class="sr">/ol</span><span class="err">>
</span>  <span class="o"><</span><span class="sr">/my-child</span><span class="err">>
,

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

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

まとめ

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

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

参考

スポンサーリンク