Angular勉強会 #5 テンプレートの補完構文 / クラスとスタイルのバインディング / ディレクティブ

## テンプレート補完構文
- バインディングで解説した `{{}}` は、実はかなり広い使い方ができ、Angularでは「補完（Interpolation）」とよばれ、またVueなどでは 「Mustache（口ひげ）」として知られている
    - 実際にはMustacheはシンプルなテンプレートエンジンである
        - https://mustache.github.io/
- 補完はあらゆる文字列が設定できる場面で利用することができ、クラス内の変数を解釈して文字列として扱うことができる

例えば下記では、Style属性をクラスの文字列プロパティとして渡している。

```html
<p style="{{ style }}">
  Hello World!!
</p>
```

```ts
export class AppComponent  {
  style = 'color: red';
}
```

上記の例でHTMLとクラスの連携は可能ではあるが、Binding構文を使っているわけではないので、クラス内の値変更には追従できない。

そのため、一般的には補完構文を利用する前に、バインディングの利用や、**ディレクティブ**の活用が必要になる。

まずは、バインディングの中でも特殊な文法を持つ属性、クラス、スタイルについて記載する。

---
## 属性のバインディング
属性（Attribute）とは、HTMLタグ内に記載されるパラメータのことである。各HTMLタグごとに属性が定義されており（例えば`img` タグには `ｓｒｃ` や `alt` 属性が、`a` タグには `href` 属性がある）、またBootstrapなどのフレームワークは独自の属性を利用してスタイルの制御を行う。

Angularでは以下のように `attribute`キワードのあとに属性名を指定することで、任意の属性の値をバインディングできる。

```html
<tr><td [attr.colspan]="colSpan">{{colSpan}} column span</td></tr>
```

---
## クラスのバインディング
HTMLのクラス属性自体は、プロパティバインディング可能となっているが、通常のバインディング形式と違い、3種類のやり方がある。

## 1. 文字列としてクラス名を設定する

```html
<p [class]="className">{{name}}</p>
```

## 2. クラス名までバインディング属性として指定し、Booleanでそのクラスの在否を設定する
```html
<p [class.red]="isRed" [class.blue]="isBlue">{{name}}</p>
```

```ts
export class AppComponent  {
  isRed = true
  isBlue = false
}
```

## 3. クラスの適用可否をHashとして設定する

```html
<p [class]="{red: isRed, blue: isBlue}">{{name}}</p>
```


---
## スタイルのバインディング
## 1. 文字列としてスタイル名を設定する
```html
<p [style]="style">
  Hello World!!
</p>
```

```ts
  style = "color: red"
```

## 2. スタイル名までバインディング属性として指定し、そのスタイルの値を設定する
```html
<p [style.color]="color">
  Hello World!!
</p>
```

```ts
  color = "red"
```

---

## ディレクティブ（Directive）とは
> directive
【形】
指示の、指導の
方向を示す
【名】
〔中央からの〕指示、命令
《言語学》〔語用論の〕命令型◆【参考】illocutionary act
【レベル】7、【発音】dəréktiv、【＠】ディレクティヴ、【変化】《複》directives、【分節】di・rec・tive
> 
> *https://eow.alc.co.jp/search?q=directive*

- ディレクティブとは、Angularのテンプレートの中で用いる特殊な司令である
- Componentと違い、HTMLの属性のように記述するという特徴がある
- **ディレクティブを用いることで、効率的なViewの制御を行うことができる**
    - Javascript / Typescript をHTMLテンプレート中に記載できるReactには対応する機能はない
    - Vue にはまさにディレクティブという名前で、同様の機能がある（v-xxxx で始まる構文がそれにあたる）

---


## 属性ディレクティブと構造ディレクティブ
- 属性ディレクティブ： DOM要素の属性に変換されるディレクティブで、DOMの属性として設定されるクラスやスタイル、値を変更することで、主に見た目の制御を行うに利用される
    - NgClass: クラスの変更
    - NgStyle: スタイルの変更
    - NgModel: 値の双方向バインディング

- 構造ディレクティブ: DOM要素そのものの生成をコントロールするディレクティブで、表示の出し分けや繰り返し表示などに用いられる
    - *ngif : 表示の制御
    - *ngfor : 繰り返し表示
    - ngSwitch / *ngSwitchCase : 表示の制御（SwitchCase）

---
## 属性ディレクティブ
### NgClass
クラスを文字列やHashではなく、Typescriptのオブジェクトとしてバインディングする機能を持つ。設定するクラスのパターンが多岐にわたる場合は、Templateではなくクラス側に持ってきたほうが可読性が上がる。


```ts
    //currentClassesをNｇClassでバインディングすると、各種プロパティの変更に応じてクラスを追加、削除できる
    this.currentClasses =  {
      saveable: this.canSave,
      modified: !this.isUnchanged,
      special:  this.isSpecial
    };
```

### NgStyle
スタイルを文字列やHashではなく、Typescriptのオブジェクトとしてバインディングする機能をもつ。

```ts
    // currentStylesをNgClassでバインディングすると、各種プロパティの変化に応じてスタイルを設定したりできる
    this.currentStyles = {
      'font-style':  this.canSave      ? 'italic' : 'normal',
      'font-weight': !this.isUnchanged ? 'bold'   : 'normal',
      'font-size':   this.isSpecial    ? '24px'   : '12px'
    };
```

---

## 演習問題
以下の要件を満たすコンポーネント `Rectangle` を作成してください。

1. width、height、colorをバインディング可能なプロパティとして持つ
    - width: 四角形の横幅
    - height: 四角形の高さ
    - color: 四角形の内部の色
2. widthとheightが一致したときに発火するイベント `onSquare` を持つ。