Angular アプリケーションプログラミング を読み、要点をメモしています。本文のコピーにならないように、自分の言葉に置き換えて記載しています。
2 章 Angular の基本
2.1 Angular を利用するための準備
2.1.1 Angular アプリケーションの基本構造
npm start コマンド:
Angular 同梱の lite-server が実行されます。この時、TypeScript が JavaScript にトランスパイルされます。
→ 2.3.1 で詳細説明。
xxx.js.map:
ソースマップファイルという。ts ファイルと js ファイルを紐付けています。デバッグ時に ts ファイルでデバッグ実行することができます。
2.2.1 モジュールについて
NgModule:
モジュール定義のためのモジュール
BrowserModule:
アプリケーションをブラウザで実行するためのモジュール
Angular モジュール:
オブジェクトをまとめるための入れ物という概念です。定義されているクラスの中は空でも動作します。(e.g. AppModule)
Angular モジュール = デコレーター + クラス
デコレーターでクラスの構成情報を設定します。
2.2.2 コンポーネント
app.component.ts 一部抜粋
@Component({ selector: 'my-app', template: `<h1>Hello {{name}}</h1>`, })
→ selector で指定されている要素(my-app)に、template で設定されているテンプレートを適用する、という意味です。変数 name の前後を囲っている {{...}} は Interpolation という構文で、変数を受け取る際の記述方法です。
2.2.3 スタートアップ
main.ts:
アプリケーション起動のための情報を設定しています。
main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
→ app.module から AppModule をインポートし、bootstrapModule メソッドで起動しています。
2.3.1 package.json
アプリケーションの情報、及びアプリケーションで利用するライブラリの情報をまとめています。
scripts コマンドには npm のサブコマンドを定義しています。
{ "name": "angular-quickstart", ... "scripts": { ... "start": "concurrently "npm run build:watch" "npm run serve"", ... },
→ npm start と入力すると TypeScript とトランスパイル、lite-server の実行及びアプリケーションのロードが行われますが、実際にはこの package.json のショートカット経由でこれら処理が呼び出されます。
3 データバインディング
3.2 Interpolation(補間)構文
{{...}} 式の内部では、グローバルオブジェクトを参照することができません。
グローバルオブジェクトは、window、document など。
3.3 プロパティバインディング
テンプレート内の HTML 要素のプロパティと、コンポーネントのプロパティ値を紐付けます。ここでは、テンプレートの a タグの href プロパティと、コンポーネントの url プロパティの値を紐付けています。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: `<a [href]="url">go to Yahoo!</a>`,//プロパティバインディング }) export class AppComponent { url = "http://www.yahoo.co.jp"; }
→ 出力結果は <a href="http://www.yahoo.co.jp">go to Yahoo!</a> になります。
3.5 イベントバインディング
3.5.1 イベントバインディングの基本
テンプレート内にハンドルするイベントと、イベントに対応するメソッドを紐付けます。ここでは click イベント発生時に myClick() メソッドが呼びされます。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: `<input type="button" [value]="myText" (click)="myClick()"/>`,//イベントハンドリング }) export class AppComponent { myText = "クリック前"; myClick() { this.myText = "クリック後"; } }
3.5.2 イベント情報の取得
JavaScript では func(evt) の形式でイベント引数を参照することができますが、Angular では $event という表記になります。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: `<input type="button" [value]="myText" (click)="myClick($event)"/>`,//イベント引数 }) export class AppComponent { myText = "クリック前"; myClick(e: MouseEvent) { this.myText = "クリック後"; console.log(e.target); } }
実行結果:
3.5.3 テンプレート参照変数
テンプレート内の要素への参照ができる仕組みです。下記では、input 要素を myInput として参照し、myInput の value プロパティを log メソッドの引数として渡しています。
@Component({ selector: 'my-app', template: `<input #myInput type="text" (input)="log(myInput.value)"/>`,//テンプレート参照変数 }) export class AppComponent { log(myInput: string) { console.log(myInput); } }
input 要素(myInput) に値を入力していくと、input イベントに紐づく log メソッドが呼び出され、コンソールに input 要素の value が出力されています。
なお、テンプレート参照変数は、テンプレート内の別の要素からも参照することができます。input イベントが発生したタイミングで、label 要素に入力文字列が変化していきます。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <input #myInput type="text" (input)="0"/> <label>「{{myInput.value}}」が入力されました。</label> `, }) export class AppComponent { }
3.5.4 キーイベントのフィルタリング(keyup.enter イベント)
Angular では Enter キーを押下したタイミングでイベントを処理するというコモンシナリオに対応する keyup.enter イベントを用意してくれています。下記例では、input 要素に値を入力し、Enter を押下したタイミングでコンソールに入力値を出力しています。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <input #myInput type="text" (keyup.enter)="log($event)"/> `, }) export class AppComponent { log(e: MouseEvent){ var target: HTMLTextAreaElement = <HTMLTextAreaElement>e.target; console.log(target.value); } }
3.6 双方向バインディング
コンポーネントの持つプロパティと UI 要素と紐付け、コンポーネント側からの変更、もしくは UI 上での変更を受け取り、ビュー ↔ コンポーネントの間で値を同期する機能です。双方向バインディングは他の開発プラットフォーム(例えば、WPF など .NET Framework)にもある、便利な機能ですね。
app.module.ts では、双方向バインディングに必要となる FormsModule をインポートします。
app.module.ts
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms';//追加 import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule, FormsModule ],//FormsModule を追加 declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
app.component.ts では、テンプレートに form 要素を配置し、その中に双方向バインディングを実装する input 要素を配置します。双方向バインディングには ngModel ディレクティブを利用します。
ここでは 2 つの input 要素を用意し、共通のコンポーネントプロパティを参照します。どちらかの input 要素で値が変更されれば、myValue の変更通知を受けて、もう一方の input 要素の値も自動的に切り替わります。
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'my-app', //template に form 要素を定義し、form 要素内に input 要素を 2 つ定義します。 //どちらかの input 要素の値を変更すると、もう一方の input 要素の値も自動的に変更されます。 //両方の input 要素は共に、ngModel を利用して myValue プロパティの値を双方向バインドしています。 template: ` <form> <input id="myText1" name="myText1" type="text" [(ngModel)]="myValue"/> <input id="myText2" name="myText2" type="text" [(ngModel)]="myValue"/> </form> ` }) export class AppComponent { myValue = "abc"; }
4. 標準パイプ/ディレクティブ
4.1 パイプ
パイプは、テキストや数値などの値をフォーマットする機能です。よく使われるフォーマットのパターンは Angular で予め用意してくれています。
下記、myText プロパティと myNumber プロパティをパイプで整形しています。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <p>{{myText | uppercase}}</p> <p>{{myText | lowercase}}</p> <p>{{myNumber | currency}}</p> <p>{{myNumber | currency: 'JPY': true}}</p> ` }) export class AppComponent { myText = "ABCdef"; myNumber = 198000; }
i18nPlural
評価の値が単数形の場合と、複数形の場合で表示を変更するためのパイプです。次の例では、配列の length に応じて表示文字列を決定しています。また、テンプレート内にバインドするプロパティに、# を含めると、評価された items.length の値を埋め込むことができます。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <p>{{items.length | i18nPlural: status}}</p> ` }) export class AppComponent { items = ["a", "b", "c", "d", "e"]; status={ "=0": "None is selected yet.", "=1": "1 item is selected.", "other": "# items are selected", } }
実行結果
4.2 ディレクティブ
4.2.1 ngIf
要素の表示、非表示切り替えに利用できます。条件が真のときには表示し、偽のときは非表示にします。
app.module.ts
forms 、FormsModule をインポートします。
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms';//追加 import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule, FormsModule ],//FormsModule を追加 declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
app.component.ts
div 要素内に *ngIf="条件" で条件判定を行います。
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <form> <label for="show">check the box</label> <input id="show" name="show" type="checkbox" [(ngModel)]="isVisible" /> </form> <div *ngIf="isVisible"> text here... </div> ` }) export class AppComponent { isVisible = false; }