SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

次世代Webアプリケーションフレームワーク「Angular」の活用

「Angular 2」コンポーネントのライフサイクルを知って使いこなす

次世代Webアプリケーションフレームワーク「Angular」の活用 第7回


ビューの初期化と変更に対応するngAfterViewInit、ngAfterVieweChecked

 ngAfterViewInitは、コンポーネントの画面(ビュー)が初期化されたとき、ngAfterViewCheckedはビューが変更されてAngular 2が検証を完了したタイミングで実行されます。図8のサンプル(004-afterview)で、実行の様子を説明します。

図8 ngAfterViewInit、ngAfterViewCheckedの実行例(004-afterview)
図8 ngAfterViewInit、ngAfterViewCheckedの実行例(004-afterview)

 このサンプルを実行すると、画面表示時点でngAfterViewInitとngAfterViewCheckedが実行されます。また、テキストボックスの値を変更すると、ngAfterViewCheckedがその都度実行されます。

図9 図8のサンプル実行時のデバッグログ(004-afterview)
図9 図8のサンプル実行時のデバッグログ(004-afterview)

 このサンプルでは、まずリスト6の子コンポーネント(ChildComponent)を利用します。このコンポーネントには1個のテキストボックスと、それに対応するchildInputプロパティが存在します。

リスト6 子コンポーネント(004-afterview/app/child.component.ts)
@Component({
  selector: "lifecycle-child"
  template: `
    <div class="component">
      <h4>ChildComponent</h4>
      childInput: <input type="text" [(ngModel)]="childInput">
    </div>
  `,
})
export class ChildComponent {
  // テキストボックスへの入力値
  childInput:string="初期値";
}

 子コンポーネントを参照するコンポーネントの実装はリスト7のようになります。

リスト7 リスト6の子コンポーネントを参照するコンポーネント(004-afterview/app/lifecycle.component.ts)
export class LifeCycleComponent
  implements AfterViewInit, AfterViewChecked {
  // 子コンポーネント ...(1)
  @ViewChild(ChildComponent) viewChild: ChildComponent;
  // 画面に表示する文字列 ...(2)
  valueFromChild:string="";
  // View初期化後に呼ばれる ...(3)
  ngAfterViewInit() {
    console.debug("ngAfterViewInit:" + this.viewChild.childInput);
  }
  // View更新ごとに呼ばれる ...(4)
  ngAfterViewChecked() {
    console.debug("ngAfterViewChecked:" + this.viewChild.childInput);
    this.displayValueFromChild();
  }
  // 子コンポーネントのchildInputの値を画面に表示する ...(5)
  displayValueFromChild() {
    // この時点でビューの処理が終わっているので、実行を遅らせる ...(6)
    if (this.valueFromChild != this.viewChild.childInput) {
      setTimeout(() => {
        this.valueFromChild=this.viewChild.childInput;
        }, 0);
    }
    // このようにすると、入力がすぐに画面に反映されない ...(7)
    // this.valueFromChild = this.viewChild.childInput;
  }
}

 (1)の@ViewChildデコレーターで、子コンポーネントをviewChild変数で参照できるようにしています。(2)はデータバインディングで画面表示する文字列変数です。(3)と(4)がライフサイクルフックの実装です。ここではviewChild.childInputの内容をデバッグログに出力しつつ、(4)では(5)で実装されるdisplayValueFromChildメソッドを実行しています。

 displayValueFromChildメソッド(5)は、子コンポーネントのchildInputプロパティを、自身のvalueFromChildにコピーして、画面表示するメソッドです。ngAfterViewCheckedライフサイクルフックの実行時点では、ビューの処理が全て完了しているため、(6)のように、Angularが次の変更検知を行うタイミングまで、setTimeoutで画面表示処理を遅らせる必要があります。

 なお、(7)のように画面表示処理を遅らせないと、図10のように、内容がすぐに画面に反映されなくなります。テキストボックスからフォーカスを外すと、Angular 2が画面の変更を検知して、入力内容を画面に反映します。

図10 ngAfterViewChecked後の変更が反映されない様子(004-afterview)
図10 ngAfterViewChecked後の変更が反映されない様子(004-afterview)

外部コンテンツの初期化と変更に対応するngAfterContentInit、ngAfterContentChecked

 ngAfterViewInit、ngAfterViewCheckedがビューに関連するのに対して、外部コンテンツのライフサイクルフックが、ngAfterContentInitとngAfterContentCheckedです。

コンポーネント外部からコンテンツを取り込むContent Projection

 Angular 2では、コンポーネントのタグ内に記述された外部コンテンツを、コンポーネント内に取り込む「Content projection」が利用できます(AngularJS 1の「Transclusion」に対応します)。例えば、リスト6の子コンポーネントに対応する<lifecycle-child>タグを、lifecycleコンポーネントの<lifecycle>タグ内に記述できます。

リスト8 コンポーネントタグ内のコンテンツ記述(005-aftercontent/app/app.component.ts)
<lifecycle>
  <!-- 子コンポーネントの表示 -->
  <lifecycle-child></lifecycle-child>
</lifecycle>

 外部コンテンツの内容は、lifecycleコンポーネントのテンプレートに記述された<ng-content>タグの箇所に反映されます。

 ngAfterContentInit、ngAfterContentCheckedは、このように記述した外部コンテンツの初期化と変更に対応するライフサイクルフックです。

ngAfterContentInit、ngAfterContentCheckedの実装例

 図11のサンプル(005-aftercontent)で、ngAfterContentInit、ngAfterContentCheckedが実行される様子を説明します。

図11 ngAfterContentInit、ngAfterContentCheckedの実行例(005-aftercontent)
図11 ngAfterContentInit、ngAfterContentCheckedの実行例(005-aftercontent)

 表示内容、デバッグログの出力タイミングは図8、9と似ていますが、このサンプルでは、ngAfterContentInit、ngAfterContentCheckedライフサイクルフックで処理を行います。

図12 図11のサンプル実行時のデバッグログ(005-aftercontent)
図12 図11のサンプル実行時のデバッグログ(005-aftercontent)

 子コンポーネントを呼び出すコンポーネントの実装はリスト9のようになります。

リスト9 Content Projectionを利用したコンポーネント(005-aftercontent/app/lifecycle.component.ts)
export class LifeCycleComponent
  implements AfterContentInit, AfterContentChecked {
  // 子コンポーネント ...(1)
  @ContentChild(ChildComponent) contentChild: ChildComponent;
  // 画面に表示する文字列
  valueFromChild:string="";
  // コンテンツ初期化後に呼ばれる ...(2)
  ngAfterContentInit() {
    console.debug("ngAfterContentInit:" + this.contentChild.childInput);
  }
  // コンテンツ更新ごとに呼ばれる ...(3)
  ngAfterContentChecked() {
    console.debug("ngAfterContentChecked:" + this.contentChild.childInput);
    this.displayValueFromChild();
  }
  // 子コンポーネントのchildInputの値を画面に表示する ...(4)
  displayValueFromChild() {
    // AfterViewフックの前なので、バインディング変数を直接変更できる ...(5)
    this.valueFromChild = this.contentChild.childInput;
  }
}

 子コンポーネントChildComponentは、対応する<lifecycle-child>タグが外部コンテンツとして記述されているので、(1)の@ContentChildデコレーターで参照します。(2)と(3)がライフサイクルフックの実装です。画面を更新する処理(4)は、ngAfterContentCheckedの実行時点でビューのライフサイクルフックがまだ実行されていないため(図1参照)、リスト7と違って(5)のように直接画面を書き換えることができます。このように、外部コンテンツのライフサイクルフックは、ビューのライフサイクルフックより前に実行されることに注意してください。

まとめ

 本記事では、Angular 2のコンポーネントで定義されているライフサイクルと、ライフサイクルフックのメソッド実装方法を説明しました。ライフサイクルを理解してライフサイクルフックを実装すれば、状態に合った適切なタイミングで処理を実行できます。

参考資料

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
次世代Webアプリケーションフレームワーク「Angular」の活用連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/10046 2017/04/24 11:02

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー