速度向上のための改善
速度向上は、Angularのバージョンアップで常に重要なテーマです。Angular 7では、以下の改善が行われました。
不要なPolyfillの自動削除
Angular 6までのAngular CLIで生成したプロジェクトでは、JavaScriptでメタデータ(引数型などの追加情報)を利用するためのPolyfill(互換性確保のためのライブラリ)を、図3の通りインポートしていました。
このPolyfillは実行中に随時コードを変換して実行するJIT(Just-in-Time)モードでは必要ですが、リリース時などで事前にコードを変換するAOT(Ahead-of-Time)モードでは不要になります。しかし、Angular 6までのプロジェクトでは、図3の記述により、リリース時に不要なインポートが行われていました。
Angular 7のAngular CLIでは、リスト1の「ng update」コマンドでAngular 6以前のプロジェクトをアップデート時に、図3のインポートを削除して、リリース時に不要なPolyfillを含まないようにします(JITモードでは自動的にPolyfillが追加されます)。
ファイルサイズの警告・エラー
Angularでは、ビルドで変換してまとめた(バンドルした)ファイルのサイズが指定サイズを超えると警告やエラーを発生する機能「Bundle Budget」が利用できます。Angular 7のAngular CLIで新規生成したプロジェクトでは、「ng build --prod」コマンドで実行されるProductionビルド時のBundle Budget設定が、プロジェクト設定ファイル(angular.json)にデフォルトで記述されるようになりました。
"production": { (略) "budgets": [ { "type": "initial", "maximumWarning": "2mb", // 2MBで警告 "maximumError": "5mb" // 5MBでエラー } ] }
Angular MaterialとCDKの機能追加
Angular Materialは、Googleが提唱するデザインガイドライン「Material Design」をAngularに提供するコンポーネントです。また、CDK(Component Dev Kit)は、Angular Materialのコア機能を切り出したものです。Angular 7のAngular MaterialとCDKには、以下の機能が追加されました。
Virtual Scrolling(仮想スクロール)
Virtual Scrolling(仮想スクロール)は、スクロールするUI要素を実現する機能です。画面に表示される周辺のHTML要素だけを動的にロードすることで、大量のデータをスムーズにスクロールできます。10万行の文字列をリストに表示する図5のサンプルで実装方法を説明します。一見普通のリストですが、開発者ツールで内容を参照すると、画面に表示されている周辺のHTML要素だけがロードされることがわかります。
「ng add @angular/material」コマンドでAngular Materialを追加後、モジュール定義ファイル(app.module.ts)をリスト3の通り記述します。Virtual Scrollingのモジュール(ScrollDispatchModule)を(1)で参照して、(2)でインポートします。
import { ScrollDispatchModule } from '@angular/cdk/scrolling'; // ...(1) (略) @NgModule({ imports: [ ScrollDispatchModule // ...(2) ], (その他の設定は略) }) export class AppModule { }
Virtual Scrollingのテンプレート記述はリスト4の通りです。
<!-- Virtual Scrollingの領域 ...(1)--> <cdk-virtual-scroll-viewport itemSize="30" class="example-viewport"> <!-- Virtual Scrollingの各要素 ...(2)--> <div *cdkVirtualFor="let item of items" class="example-item"> {{item}} </div> </cdk-virtual-scroll-viewport>
(1)の<cdk-virtual-scroll-viewport>タグがVirtual Scrollingの領域を表します。itemSize(30)は、1行あたりの高さ(単位はpx)です。(2)では、Angularで繰り返しを表す*ngForの代わりに*cdkVirtualFor属性(ディレクティブ)を設定して、データ配列itemsの各要素を表示する<div>タグを記述します。itemsは、コンポーネント(app.component.ts)でリスト5の通り記述して、要素数10万の配列を生成します。
items = Array.from({length: 100000}).map((_, i) => `${i}番目の行`);
Virtual Scrollingの詳細は、公式ドキュメントも参照してください。
ドラッグアンドドロップ
ドラッグアンドドロップの機能がCDKに追加されました。最初に、単純なドラッグアンドドロップの例を図6のサンプルで説明します。四角形をマウスでドラッグできます。
ドラッグアンドドロップを利用するには、プロジェクトにAngular Materialを設定したあと、ドラッグアンドドロップのモジュール(DragDropModule)をapp.module.tsに設定します(詳細はサンプルコード参照)。ドラッグする要素は、リスト6の通り記述します。要素にcdkDrag属性(ディレクティブ)を設定して、ドラッグ可能にします。
<div class="example-box" cdkDrag> ドラッグで移動できます </div>
次に、ドラッグアンドドロップでリストを並び替える図7のサンプルを説明します。
リストのテンプレート記述は、リスト7の通りです。
<!-- 並び替えるリスト ...(1)--> <div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)"> <!-- リストの各行 ...(2)--> <div class="example-box" *ngFor="let phone of phones" cdkDrag>{{phone}}</div> </div>
(1)がリストに対応します。cdkDropList属性(ディレクティブ)を設定するとドラッグアンドドロップで並び替えができるようになります。また、ここでは並び替え時のイベント(cdkDropListDropped)に、後述するdropメソッドを指定しています。(2)はリストの各行に対応し、cdkDrag属性(ディレクティブ)を設定してドラッグ可能にします。各行には後述するデータ配列phonesの各要素を表示します。
リスト7に対応するコンポーネントの実装はリスト8の通りです。
export class AppComponent { // リストに表示するデータ ...(1) phones = [ 'Apple iPhone XS', 'Apple iPhone XS Max', (略) ]; // ドロップ時の処理 ...(2) drop(event: CdkDragDrop<string[]>) { // 配列の並び替え ...(3) moveItemInArray(this.phones, event.previousIndex, event.currentIndex); } }
(1)がリストに表示するデータの配列です。(2)はリストの行をドロップしたときの処理で、引数eventから並び替え前のインデックス(previousIndex)と並び替え後のインデックス(currentIndex)を取得して、CDKが提供する(3)のmoveItemInArrayメソッドで並び替えています。
ドラッグアンドドロップの詳細は、公式ドキュメントも参照してください。
セレクトボックスのselectタグ対応
Angular Materialのフォーム(mat-form-field)で実現するセレクトボックスは、従来はAngular Material独自タグ(mat-select)だけが利用できましたが、Angular 7のAngular Materialでは、HTMLのselectタグも利用できるようになりました。図8のサンプル(p006-mat-select)で利用方法を説明します。なお、Edgeブラウザーではmat-selectのセレクトボックス表示が乱れる(意図せずブラウザー画面の横幅いっぱいに表示される)ため、図8はChromeブラウザーで実行しています。
テンプレート記述は、リスト9の通りです。(1)がAngular Materialのmat-selectとmat-optionタグ、(2)がHTMLのselectとoptionタグでの記述例です。リスト9を動作させるには、Angular MaterialのMatSelectModuleとMatInputModuleモジュールをapp.module.tsに設定する必要があります。詳細はサンプルコードを参照してください。
<mat-form-field><!-- 独自のmat-select、mat-optionタグ ...(1) --> <mat-select placeholder="スマートフォン会社"> <mat-option value="apple">Apple</mat-option> (略) </mat-select> </mat-form-field> <mat-form-field><!-- HTMLのselect、optionタグ ...(2)--> <select matNativeControl placeholder="スマートフォン会社"> <option value="apple">Apple</option> (略) </select> </mat-form-field>
Angular Material独自タグはアニメーションなどリッチなユーザー体験を提供する一方、HTMLのselectタグは動作速度やアクセシビリティーなどの点で優れており、要件に応じて開発者が選択できます。