Angular 7 と Angular Material と Material Design Icons を試した
Angular7 がリリースされたので、そのお試しがてら、Angular Material と Material Design Icons を導入して遊んでみた。
目次
- Angular7 とは
- Angular Material とは
- Material Design Icons とは
- Angular7 アプリを新規作成する
- Angular Material を導入する
- Material Design Icons を導入する
- サンプルコードを書いてみる
- Material Desgin Icons を使ってみる
- お試しできた
Angular7 とは
Angular7 は 2018-10-19 にリリースされた。
Angular6 からの破壊的変更はほとんどなく、Angular Update Guide で指示されるマイグレーション作業もほぼなし。ちなみに Angular6 は2018年10月から LTS モードになっていて、同時に Angular4 は LTS が終了。もう Angular4 系について書かれた書籍やサイトは「サポートが終了した古いフレームワークについて触れた記事」と化すのか…。
今回は @angular/cli
を本稿執筆時点の最新版である v7.0.2 にアップデートし、そこから ng new
コマンドで新規に Angular7 アプリを生成しようと思う。
Angular Material とは
Angular Material とは、Angular アプリで Material Design を実現するためのコンポーネント集。NgModule
として各種コンポーネントをインポートし、マテリアル・デザインなボタンや Card UI などを実装できる。
コレまで Twitter Bootstrap ばっかりで、マテリアル・デザインに触れてこなかったのだが、Bootstrap がより「Web サイトっぽさ」を持つ UI コンポーネントが多いのに対して、マテリアル・デザインは「ネイティブアプリっぽさ」があるように感じる。元々の設計思想として、「レスポンシブルデザイン」とかいうよりは「様々な種類のデバイスで操作感に統一性をもたせる」ことが狙いっぽい。
Material Design Icons とは
Material Design Icons とは、Material Design の中で使われるアイコン集。Bootstrap3 の Glyphicon や、Font Awesome みたいなモノの Material Desgin 版だと思って良い。どうもコレだけ Angular Material の中には含まれていないようなので、別途インストールしてみる。
Angular7 アプリを新規作成する
それではいよいよ、Angular7 アプリを作成し、Angular Material と Material Design Icons を導入してみようと思う。OS は macOS Mojave で試したが、Windows10 でも同じ。
Node.js、npm の実行環境は以下のとおり。Angular7 からは Node.js v10 がサポートされたようだ。
$ node -v
v10.7.0
$ npm -v
6.1.0
まずは Angular CLI をグローバルインストールする。
$ npm install -g @angular/cli
# バージョン確認
$ ng version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 7.0.2
Node: 10.7.0
OS: darwin x64
Angular:
...
Package Version
------------------------------------------------------
@angular-devkit/architect 0.10.2
@angular-devkit/core 7.0.2
@angular-devkit/schematics 7.0.2
@schematics/angular 7.0.2
@schematics/update 0.10.2
rxjs 6.3.3
typescript 3.1.3
次に ng new
コマンドでプロジェクトを作成する。Angular7 から、--style
と --routing
についてはオプション引数で指定せず対話形式でも設定できるようになった。
$ ng new
? What name would you like to use for the project? practice-material
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS [ http://sass-lang.com ]
CREATE practice-material/README.md (1033 bytes)
CREATE practice-material/angular.json (3958 bytes)
CREATE practice-material/package.json (1324 bytes)
# …以下略…
プロジェクトが生成できたので、生成したプロジェクトのディレクトリに移動する。
Angular Material を導入する
続いて Angular Material を導入する。
- 参考 : Angular Material … 主に参考にしたのはこの公式リファレンス。
公式リファレンスによると ng add
で追加できるようだったので試してみたのだが、Cannot read property 'endTag' of undefined
エラーが出て処理が完了しなかった。
$ npm run ng add @angular/material
> practice-material@0.0.0 ng /Users/Neo/Me/Practices/practice-material
> ng "add" "@angular/material"
Installing packages for tooling via npm.
? Enter a prebuilt theme name, or "custom" for a custom theme: indigo-pink
? Set up HammerJS for gesture recognition? Yes
? Set up browser animations for Angular Material? Yes
UPDATE package.json (1447 bytes)
up to date in 9.24s
HammerJS is already imported in the project main file (src/main.ts).
Cannot read property 'endTag' of undefined
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! practice-material@0.0.0 ng: `ng "add" "@angular/material"`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the practice-material@0.0.0 ng script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/Neo/.npm/_logs/2018-10-24T05_11_12_732Z-debug.log
package.json
の書き換えだけ行われていて、次のように @angular/cdk
・@angular/material
・hammerjs
が追加されていた。
"dependencies": {
"@angular/animations": "~7.0.0",
+ "@angular/cdk": "^7.0.1",
"@angular/common": "~7.0.0",
"@angular/compiler": "~7.0.0",
"@angular/core": "~7.0.0",
"@angular/forms": "~7.0.0",
"@angular/http": "~7.0.0",
+ "@angular/material": "7.0.1",
"@angular/platform-browser": "~7.0.0",
"@angular/platform-browser-dynamic": "~7.0.0",
"@angular/router": "~7.0.0",
"core-js": "^2.5.4",
+ "hammerjs": "^2.0.8",
"rxjs": "~6.3.3",
"zone.js": "~0.8.26"
},
なんだか違和感があるので、素直に npm install
からの手作業でやり直すことにする。
$ npm install --save @angular/material @angular/cdk hammerjs
- UI をアニメーションさせるには
@angular/animations
も必要だが、ng new
時点で入っていたので無視 - Hammer.js は、スライダーなど一部の UI でタッチジェスチャーを実現するために必要になる。
これで npm install
は完了。
続いて、AppModule
に UI アニメーション用のモジュールとして BrowserAnimationsModule
をインポートする。もしアニメーションさせたくない場合は NoopAnimationsModule
をインポートする。
/* app.module.ts */
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
// 追加
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
// もしくは以下
// import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule, // もしくは NoopAnimationsModule
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
次に styles.scss
でテーマを設定する。用意されているテーマは以下の4種類。
indigo-pink.css
deeppurple-amber.css
pink-bluegrey.css
purple-green.css
テーマごとのカラーリングは以下の記事にスクリーンショットがあるので確認できる。
/* styles.scss */
// Angular Material : Indigo Pink
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
最後に、Hammer.js をインポートする。普段と違い、src/main.ts
に追記するので注意。
/* main.ts */
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
// 以下を追記
import 'hammerjs';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
コレで Angular Material を利用する準備は整った。
Material Design Icons を導入する
引き続き、Material Design Icons も導入してみよう。
公式のリファレンスでは link
要素を追加して CDN から利用するように書かれているのだが、今回は npm install
して使ってみようと思う。
# 本稿執筆時点では v3.0.1 がインストールされた
$ npm install --save material-design-icons
次に styles.scss
でインポート。
/* styles.scss */
// 先程追加した Angular Material のテーマ
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
// Material Desgin Icons のスタイルシートファイルをインポートする
@import '~material-design-icons/iconfont/material-icons.css';
コレで Material Design Icons を使うための準備が整った。
サンプルコードを書いてみる
今回は簡単にするため、AppComponent
に直接コードを書いて、Angular Material および Material Design Icons を試してみる。
まずは Angular Material だが、コレは使用したいコンポーネントに合わせて NgModule
をインポートする必要がある。公式の API リファレンスに import
する NgModule
クラスが記載されているので、よく確認する。
- 参考 : Angular Material
今回はこのあと色々なコンポーネントを書いていくため、以下のような AppModule
にする。
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
// Angular Material
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatInputModule } from '@angular/material/input';
import { MatCardModule } from '@angular/material/card';
import { MatSliderModule } from '@angular/material/slider';
import { MatToolbarModule } from '@angular/material/toolbar';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
BrowserAnimationsModule, // For Angular Material
FormsModule,
ReactiveFormsModule,
// Angular Material --------------------
MatButtonModule,
MatCheckboxModule,
MatInputModule,
MatCardModule,
MatSliderModule,
MatToolbarModule,
// App --------------------
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
次に HTML 部分。
<!-- app.component.html -->
<!-- ボタン -->
<p>
<button mat-raised-button>Basic</button>
<button mat-raised-button color="primary">Primary</button>
<button mat-raised-button color="accent">Accent</button>
<button mat-raised-button color="warn">Warn</button>
<button mat-raised-button disabled>Disabled</button>
<a mat-raised-button [routerLink]="['/']">Link</a>
</p>
<!-- カード -->
<mat-card>
<mat-card-header>
<mat-card-title>Slider Configuration</mat-card-title>
<mat-card-subtitle>Slider Example</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<section>
<!-- テキストボックス -->
<mat-form-field><input matInput type="number" placeholder="Value" [(ngModel)]="value"></mat-form-field>
<mat-form-field><input matInput type="number" placeholder="Min value" [(ngModel)]="min"></mat-form-field>
<mat-form-field><input matInput type="number" placeholder="Max value" [(ngModel)]="max"></mat-form-field>
<mat-form-field><input matInput type="number" placeholder="Step size" [(ngModel)]="step"></mat-form-field>
</section>
<section>
<!-- チェックボックス -->
<mat-checkbox [(ngModel)]="showTicks">Show ticks</mat-checkbox>
<mat-checkbox [(ngModel)]="autoTicks" *ngIf="showTicks">Auto ticks</mat-checkbox>
<mat-form-field *ngIf="showTicks && !autoTicks"><input matInput type="number" placeholder="Tick interval" [(ngModel)]="tickInterval"></mat-form-field>
</section>
<section><mat-checkbox [(ngModel)]="thumbLabel">Show thumb label</mat-checkbox></section>
<section><mat-checkbox [(ngModel)]="vertical">Vertical</mat-checkbox></section>
<section><mat-checkbox [(ngModel)]="invert">Inverted</mat-checkbox></section>
<section><mat-checkbox [(ngModel)]="disabled">Disabled</mat-checkbox></section>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card-content>
<h2>Result</h2>
<!-- スライダー (Hammer.js 利用) -->
<mat-slider [(ngModel)]="value" [disabled]="disabled" [invert]="invert" [max]="max" [min]="min" [step]="step" [thumbLabel]="thumbLabel" [tickInterval]="tickInterval" [vertical]="vertical"></mat-slider>
</mat-card-content>
</mat-card>
Button は単独で配置。Slider のオプションを切り替えるため Input、Checkbox を利用。フォーム部品を使うために Form Field を import
し、Card でレイアウトを調整した。このコードはほとんど公式の API リファレンスにあるサンプルコードの流用。ちなみに、mat-*
なコンポーネント名称が最近の Angular Material の仕様で、昔は md-*
というコンポーネント名だったそうなので、参考にする文献の年代に注意。
続いてコレに対応するプロパティを TypeScript 側に書く。
/* app.component.ts */
import { Component } from '@angular/core';
import { coerceNumberProperty } from '@angular/cdk/coercion';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
public autoTicks = false;
public disabled = false;
public invert = false;
public max = 100;
public min = 0;
public showTicks = false;
public step = 1;
public thumbLabel = false;
public value = 0;
public vertical = false;
private _tickInterval = 1;
get tickInterval(): number | 'auto' {
return this.showTicks ? (this.autoTicks ? 'auto' : this._tickInterval) : 0;
}
set tickInterval(value) {
this._tickInterval = coerceNumberProperty(value);
}
}
公式のサンプルコードの受け売り。coerceNumberProperty()
っていうのは NaN
を弾くためのちょっとしたヘルパーメソッド。常に number
を返すためのモノと思っておけば良い。
コレで完成。動作するスライダーができた。
Material Desgin Icons を使ってみる
Material Design Icons の方は、以下のページより使用可能なアイコンを確認できる。
アイコンをクリックし、画面左下の「Selected Icon」を選ぶと、コピペで使えるコードが表示される。
Material Design Icons は、Bootstrap Glyphicons や Font Awesome のようにクラス名でアイコンを指定するのではなく、<i class="material-icons"></i>
内に書いた文字列によってアイコン文字が生成される、という特殊な作りになっている。
HTML に、以下のようにいくつかアイコンを書いてみよう。
<!-- app.component.html -->
<i class="material-icons">code</i>
<i class="material-icons">done</i>
<i class="material-icons">favorite</i>
このように実装すると、code
で「< >
」こんなアイコン、done
で「レ点」チェック、favorite
でハートマークが表示されることが確認できる。いずれも .material-icons
というクラス名で実装してあることが分かるだろう。
このような特殊なウェブフォントなので、オススメはしないが、以下のように書いても同じ3つのアイコンが表示される。
<!-- スペースがなくても良い -->
<i class="material-icons">codedonefavorite</i>
<!-- スペース有 -->
<i class="material-icons">code done favorite</i>
アイコンを含む文字列をコピーしてメモ帳などに貼り付けると、中に書いた文字列が登場するのが面白い。
お試しできた
今回はココまで。
Angular7 は Angular6 からの劇的な変化はないものの、AngularCLI はより親切な作りになっているし、今回は試していないが複数プロジェクトやライブラリの作成も良い感じになってきた。Tree-Shaking を始めとするバンドルサイズ (ビルドした最終成果物ファイルのサイズ) を小さくする改良も重ねられていて良い。
Angular Material (Material Design)、なかなか良いではないか…。ただ、Angular Material は Bootstrap のようにデフォルトスタイルを調整したりする機能はなく、本当にコンポーネント単位で完結しているので、ページレイアウトなんかはスクラッチで実装しないといけない部分がある。今回試してはいないが、Normalize.css や Bootstrap (Reboot) でリセット / ノーマライズと全体の調整を任せておくやり方で大丈夫みたい。
- 参考 : angular - How do you reset/normalize your css using google material design (angular4)? - Stack Overflow
- 参考 : The Best Parts of Bootstrap 4 You are Missing in Angular Material … Bootstrap4 Reboot 適用前後のキャプチャアリ
- 参考 : Angular Forms - Bootstrap 4 & Material Design. Examples & tutorial - Material Design for Bootstrap … Bootstrap4 と Angular Material で同様のフォームを実装したサンプルがいくつかある。というか、Bootstrap4 を Material Desgin にする
angular-bootstrap-md
というライブラリのページらしい。 - 参考 : How To Build Responsive Layouts With Bootstrap 4 and Angular 6 📐
Material Design Icons も面白い。当然 Angular Material と調和の取れるアイコンが多いので、使いやすい。