Array を指定した個数で分割する ChunkPipe を作った
作ったってほどの話ではないです。
Bootstrap を使っていると、Array に入っている要素からグリッドを作成していことがあります。あるんです。
<!-- こんなデータがあったとして let items = [ { name: "はてなブログ", url: "http://hatenablog.com/" }, { name: "はてなブックマーク", url: "http://b.hatena.ne.jp/" }, { name: "人力検索はてな", url: "http://q.hatena.ne.jp/" }, { name: "はてなアンテナ", url: "http://a.hatena.ne.jp/" }, { name: "はてなキーワード", url: "http://k.hatena.ne.jp/" } ]; --> <div class="container"> <div class="row"> <!-- container > row の中に col-md-4 のグリッドが 5 つ入ってしまう --> <div class="col-md-4" *ngFor="let item of items"> <p><a [href]="item.url">{{ item.name }}</a></p> </div> </div> </div>
Bootstrap 的には以下のように定義するべきだと思います。 (テンプレート展開後)
<div class="container"> <div class="row"> <div class="col-md-4"> <p><a href="http://hatenablog.com/">はてなブログ</a></p> </div> <div class="col-md-4"> <p><a href="http://b.hatena.ne.jp/">はてなブックマーク</a></p> </div> <div class="col-md-4"> <p><a href="http://q.hatena.ne.jp/">人力検索はてな</a></p> </div> </div> <div class="row"> <div class="col-md-4"> <p><a href="http://a.hatena.ne.jp/">はてなアンテナ</a></p> </div> <div class="col-md-4"> <p><a href="http://k.hatena.ne.jp/">はてなキーワード</a></p> </div> </div> </div>
div.row
と div.col-md-4
の 2 つのループが登場することになります。
まず元の Array を 3 個に分割して、その要素をループして・・・となりますが、元の Array を分割する処理をどこに書くか ? という問題が起きました。
今回は、Array を指定した個数で分割する ChunkPipe
を定義して使ってみようと思います。
定義
ChunkPipe
の定義は以下のとおりです。
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'chunk' }) export class ChunkPipe implements PipeTransform { transform(value: any, args?: any): any { let array = value; let count = args; let len = Math.round(array.length / count); let chunked = []; for (let i = 0; i < len; i++) { chunked.push(array.slice(i * count, i * count + count)) } return chunked; } }
PipeTransform
を実装した ChunkPipe
クラスを定義します。
Pipe の定義方法は以下のドキュメントを参照してください。
このような処理は、PHP には array_chunk
関数で用意されています。
もちろん、NPM にもあります。
使い方
row
のループをする際に、ChunkPipe
でまず Array を分割して、その後分割した Array で div.col-md-4
をループします。
<div class="container"> <!-- row を ngFor でループする際に、chunk:3 を指定し、要素数が 3 個の Array を生成する。 --> <div class="row" *ngFor="let chunked of items | chunk:3"> <!-- col-md-4 をループする --> <div class="col-md-4" *ngFor="let item of chunked"> <p><a [href]="item.url">{{ item.name }}</a></p> </div> </div> </div>
すると、あるべき姿の HTML を生成することができます。
注意点
今回定義した Pipe は、pure
な Pipe を定義しています。
Array 自体や Array の中身を変更しても画面に表示されない場合、impure
なPipe に変更すると上手くいくかもしれません。
pure
や impure
については、@mitsuruog さんのブログ記事で解説されています。
ただし、性能はちょっと悪くなる可能性もあります。
まとめ
Angular で Array を表示する際のちょっとした小ネタでした。 Component 側で分割した Array を作っている方などはぜひ使ってみてください。