Angularで複数の要素を「繰り返し」出力するには?(ngFor)Angular TIPS

配列の内容を順に出力できるngForディレクティブ(=ngForOfディレクティブ)と、ダミーのコンテナー要素(<ng-container>)を使うことで、複数の要素群をまとめて繰り返し出力する方法を説明する。

» 2017年11月13日 05時00分 公開
[山田祥寛]
「Angular TIPS」のインデックス

連載目次

現在では、Web標準技術を利用したアプリ開発が広く普及し、そのためのフレームワークも多数存在しています。その中でも主流のフレームワークの1つである「Angular」を活用し、そのための知識を備えることには大きな意味があります。本連載は、Angularユーザーに向けて、その使いこなしTIPSを紹介するものです。なお、本連載は「Build Insider」で公開していた連載「Angular Tips」を同サイトおよび筆者の了解を得たうえで、本フォーラムに移行したものです。記事はBuild Insiderで公開した状態のまま移行しているため、用語統一などの基準が@ITの通常の記事とは異なる場合があります。


【対応バージョン】

 Angular 4以降。v4時点で執筆しました。


 ngForディレクティブ*1は、ディレクティブを指定した要素の開始タグから終了タグまでをひとまとまりとして、出力を繰り返します。その性質上、複数の要素をngForで出力することはできません。

*1 ngForディレクティブは、厳密にはngForOfディレクティブとなっています。詳しくは前回のTIPSをご参照ください。


 例えば以下は、<dt>/<dd>要素を繰り返し出力することを意図したコードですが、そうはなりません。<dt>要素だけを繰り返し出力します。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
  <dl>
  <dt *ngFor="let article of articles">{{article.title}}</dt>
  <dd>{{article.url}} /( {{article.released | date: 'mediumDate'}}</dd>
  </dl>
  `,
})
export class AppComponent  { 
  articles = [
    {
      url: 'http://www.buildinsider.net/web/jqueryref',
      title: 'jQuery逆引きリファレンス',
      author: 'WINGSプロジェクト',
      released: new Date(2017, 10, 1)
    },
    ……中略……
  ]  
}

リスト1 複数の要素セットを繰り返し出力するためのコード(ダメな例。app.component.ts)

<dl>
  <!--bindings={
  "ng-reflect-ng-for-of": "[object Object],[object Object"
}-->
  <dt>jQuery逆引きリファレンス</dt>
  <dt>Angular TIPS</dt>
  <dt>jQuery Mobile逆引きリファレンス</dt>
  <dt>Web業界で働くためのPHP入門</dt>
  <dt>Tessel 2ではじめるセンサー電子工作入門</dt>
  <dd></dd>
</dl>

リスト2 <dt>要素だけが繰り返しの対象になっている(開発者ツールから確認)

 果たして、<dt>要素だけが繰り返しの対象になっていることが確認できます*2。この対策として、繰り返したい要素群をまとめて<div>要素などでくくるという方法が考えられます。しかし、Angular側の都合で余計な要素を増やすのは、あまり望ましい状態ではありません。

*2 開発者ツール上でも「Cannot read property 'url' of undefined」のようなエラーが表示されますが、<dd>要素がngForループの外になっているのが原因です。現時点では無視して構いません。


 このような場合には、ダミーのコンテナー要素として<ng-container>要素を利用してください。これによって、ngForディレクティブは<ng-container>要素配下の子要素群を繰り返し出力します(=<ng-container>要素そのものは出力しません)。

 以下は、その具体的なコードです。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
  <dl>
  <ng-container *ngFor="let article of articles">
    <dt>{{article.title}}</dt>
    <dd>{{article.url}}({{article.released | date: 'mediumDate'}})</dd>
  </ng-container>
  </dl>
  `,
})

リスト3 複数の要素セットを繰り返し出力するためのコード(修正版。app.component.ts)

<dl>
  <!--bindings={
  "ng-reflect-ng-for-of": "[object Object],[object Object"
}-->
    <!---->
    <dt>jQuery逆引きリファレンス</dt>
    <dd>http://www.buildinsider.net/web/jqueryref(2017年11月1日)</dd>
  <!---->
    <dt>Angular TIPS</dt>
    <dd>http://www.buildinsider.net/web/angulartips(2017年10月10日)</dd>
  <!---->
    <dt>jQuery Mobile逆引きリファレンス</dt>
    <dd>http://www.buildinsider.net/web/jquerymobileref(2016年3月9日)</dd>
  <!---->
    <dt>Web業界で働くためのPHP入門</dt>
    <dd>http://www.atmarkit.co.jp/ait/series/1432/(2017年3月27日)</dd>
  <!---->
    <dt>Tessel 2ではじめるセンサー電子工作入門</dt>
    <dd>hhttps://codezine.jp/article/corner/693(2017年3月9日)</dd>
</dl>

リスト4 <dt>/<dd>要素が繰り返しの対象になっている(開発者ツールから確認)

 今度は、<dt>〜<dd>要素の範囲で繰り返し処理が実行されていることが確認できます。

処理対象:構造ディレクティブ(Structural directives) カテゴリ:基本
処理対象:<ng-container>|マイクロシンタックス(Microsyntax) カテゴリ:構造ディレクティブ(Structural directives)
処理対象:テンプレート構文(Template Syntax) カテゴリ:基本
処理対象:NgFor カテゴリ:テンプレート構文(Template Syntax) > ビルトイン構造ディレクティブ(Built-in structural directives)
処理対象:*ngForマイクロシンタックス(*ngFor microsyntax) カテゴリ:テンプレート構文(Template Syntax) > ビルトイン構造ディレクティブ(Built-in structural directives) > NgFor
API:NgForOf(*ngFor) カテゴリ:@angular > common > DIRECTIVE(ディレクティブ)


「Angular TIPS」のインデックス

Angular TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。