[AngularJS] 1. 初めの一歩

---
[目次](http://qiita.com/Koizumi-Greenwich/items/3e327e3331b2f728797e)
≫次の記事 2.[モジュール、コントローラー、サービス≪改訂≫](http://qiita.com/Koizumi-Greenwich/items/789276986bc3ff967eaa)

---

*※最下部のサンプルコードをHTMLファイルとして保存し、ブラウザで表示、ブラウザの開発ツールなどでソースコードを確認しながら読んでください。*

#AngularJSとは？
AngularJS は Google がリリースしている JavaScript MVCフレームワークです。
強力なテンプレート機能を備えており、JavaScript によるフロントエンド アプリケーション開発を大幅に簡略化、効率化します。

#AngularJSの入手
AngularJSの本体jsファイルは[公式サイト](https://angularjs.org)からダウンロードできます。公式の GitHub からも pull できます。
あるいは Google の CDN から読み込んで利用するのがオススメです。

```html:sample01.html
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
```

このようにAngularJSのjsファイルを読み込ませるだけで、AngularJSを利用する準備は完了です。

#初めの一歩
##ng-app ディレクティブ
最初に行わなければならないのは、HTMLのどの部分をAngularJSのテンプレートとして扱うか、を決めることです。
AngularJSテンプレートとして扱う部分を囲むタグに **ng-app** という属性を記述してください。

```html:sample01.html
<div ng-app>
  〜 AngularJSテンプレート 〜
</div>
```

HTMLファイル全体をテンプレート化するならば htmlタグ や bodyタグ に記述するのがよいでしょう。

AngularJSではこのような **ng-xxxx** という属性を **ディレクティブ** と呼びます。
**ng-app** ディレクティブは、「この部分をAngularJSで処理するよ！」という宣言になります。

##入力フィールド
次にデータ入力フィールドを2つ作りましょう。
商品などの単価と数量を入力するフィールドです。

```html:sample01.html
<div ng-app>
    <form name="form">
        単価: <input type="number" name="price" ng-model="price" required> 円<br>
        数量: <input type="number" name="qty" ng-model="qty" required> 個<br>
    </form>
</div>
```

***Tips***
*HTML5 から input要素に数多くの type が追加されました。`type="number"` は数値のみを入力できるフィールドになります。また required属性も HTML5 から追加された「必須項目」を表す属性です。
[HTML5のフォーム要素](http://www.htmq.com/html5/index.shtml#for)*


フォーム入力フィールドには **ng-model** というディレクティブを設定します。
**ng-model** は AngularJS の *特殊な変数とテンプレートを紐付ける* ディレクティブで、特殊な変数のことを「 **モデル変数** （あるいは単にモデル）」、紐付けることを「 **バインド** 」と言います。

ng-model ディレクティブでは、モデル変数名を指定します。

```text:書式
<input|textarea|select|button .... ng-model="モデル変数名">
```

また、モデル変数には ハッシュオブジェクト（連想配列）要素を指定することもできます。

```text:書式
<input|textarea|select|button .... ng-model="オブジェクト.キー名">
```

フィールドに値が入力されると、自動的に紐付けられたモデル変数の値が更新されます。

##モデル変数の出力
モデルの値を出力するには2つの方法があります。

### {{ ... }} タグ
1つは最も簡単な方法で `{{ ... }}` というAngularJSのテンプレートタグを使用する方法です。

```text:書式
{{モデル変数 または 式}}
{{モデル変数 または 式 | フィルタ}}
```

*フィルタ* は出力時に文字列を加工するための機能で、AngularJS標準でいくつかのフィルタが用意されています。また独自のフィルタを作ることも可能です。

```html:sample01.html
合計: {{price * qty | number}} 円
```

この例では前述の2つの入力フィールドの値を乗算した後、 **number** フィルタで数値書式（3桁ごとに "," を入れる）に加工して出力します。

モデル変数の出力時には、< や > などのHTML特殊文字は自動的にエンティティ（&amp;lt;、&amp;gt; など）にエスケープします。

### ng-bind、ng-bind-html
もう1つはディレクティブを使用する方法です。&lt;span&gt;要素などで出力箇所を囲むタグに **ng-bind** または **ng-bind-html** ディレクティブを指定します。

```text:書式
< ... ng-bind="モデル変数 または 式 | フィルタ">
< ... ng-bind-html="モデル変数 または 式 | フィルタ">
```

モデル変数、式、フィルタの記述をディレクティブの属性値として記述するほかは、`{{ ... }}` タグと変わりありません。

- ng-bind
	- `{{ ... }}`の動作と全く同じです。「{」「}」を記述したくない場合（Smartyテンプレートなど）に便利です。
- ng-bind-html
	- HTML特殊文字を **エスケープしません**。HTMLタグをそのまま出力したい場合、例えば複数行のテキストを &lt;br&gt;タグなどで改行させたい場合などに用います。ただしこのディレクティブの使用には、あらかじめ Strict Contextual Escaping(SCE)機能の設定が必要です（別途解説します）。

```html:sample01.html
    商品名: <input type="text" name="itemName" ng-model="itemName" required><br>
    商品: {{itemName}}<br>
```

このように入力値をモデルへ、モデルを出力へと紐付ける仕組みを **データバインディング** と言います。

##スタイルの制御
上記のコードをブラウザで表示し、ブラウザの開発ツールなどで確認すると、フィールド要素に **ng-xxxx** というclass が追加されているのがわかります。
これらは AngularJS が自動的に追加する class で、このclassを使ってスタイルを制御することができます。

###代表的なng-xxxクラス
- ng-valid | ng-invalid
	- 入力が **適切(valid)** または **不適切(invalid)** な場合にセットされます。例えば、`type="email"`のフィールドの値がメールアドレスの書式ではない場合などです。
- ng-valid-required | ng-valid-required
	- 必須項目（required属性が設定されているフィールド）の入力の有無によってセットされます。
- ng-valid-[type属性値] | ng-invalid-[type属性値]
	- `type="number"` や `type="email"` など、フィールドの type によってセットされます。例）ng-valid-email ng-valid-number

```HTML:sample01.html
<style>
    input.ng-invalid {
        background-color: #ffcccc;
    }
</style>
```

##入力値のバリデーション
###form要素
AngularJSでは form要素 を **FormController** というオブジェクトで管理します。name属性を指定することでそのフォームの FormControllerオブジェクトにアクセスできるようになります。

```text:書式
<form name="FormControllerオブジェクト名"> ... </form>
```

####ng-formディレクティブ
**ng-form**ディレクティブは、form以外の要素を FormControllerオブジェクト化したい場合に使用します。このディレクティブを指定することで、 **どんなHTML要素でも**FormControllerオブジェクトにすることができます。
たとえば、1つのform要素内のフィールドを、いくつかのグループに分けてそれぞれを別のFormControllerオブジェクトで管理したい場合、すなわちフォームの入れ子を実現したいとき（※HTMLではform要素の入れ子は許されていない）などに便利です。

###form要素のクラス
form要素にも自動的に前述の **ng-xxx** クラスが追加され、フィールドへの入力値によって変化します。これによりフォーム全体のスタイルを制御することができます。

###FormControllerのプロパティ
フォームのFormControllerオブジェクトのプロパティによって、フォーム全体、および各フィールドのバリデーション状況を把握することができます。

```text:書式
FormControllerオブジェクト名.$valid
FormControllerオブジェクト名.フィールド名.$valid
FormControllerオブジェクト名.フィールド名.$error.バリデーション種別
```

- FormControllerオブジェクト名.$valid
	- フォーム内のいずれかのフィールドに不適切な値が入力されている場合に **false** となります。すべてのフィールドが適切であれば **true** です。
- FormControllerオブジェクト名.フィールド名.$valid
	- 指定したフィールド（フィールドの name属性）のバリデーション結果を持つプロパティです。値が適切であれば **true**、不適切であれば **false** となります。
- FormControllerオブジェクト名.フィールド名.$error.バリデーション種別
	- 指定したフィールドの、バリデーション種別（required, number, email など）ごとの結果を持つプロパティです。 **エラーがある場合**に **true** になります。（※エラーが無い場合はプロパティそのものがセットされません）

###ng-show/ng-hide と ng-if
条件式によってHTML要素の表示・非表示を制御するディレクティブです。条件式が **true** の場合に要素が表示されます。

```text:書式
< ... ng-show="条件式"> .... </...>
< ... ng-if="条件式"> .... </...>
```

- ng-show
	- CSSの visibility プロパティによって制御されます。したがって非表示でもHTML要素そのものは削除されず `visibility: hidden` で隠されているだけです。
- ng-hide
	- ng-show と逆の動作をします。
- ng-if
	- HTML要素そのものを追加・削除することで制御されます。

###バリデーションエラーメッセージを表示する
以上のFormControllerプロパティとng-show/ng-ifディレクティブを使って、バリデーションエラーメッセージの表示・非表示を行ってみましょう。

```html:sample01.html
        <span ng-hide="form.$valid" class="invalid">未入力の項目があります</span><br>
        商品名: <input type="text" name="itemName" ng-model="itemName" required>
        <span ng-show="form.itemName.$error.required" class="invalid">必須項目です。入力してください</span><br>
        単価: <input type="number" name="price" ng-model="price" required> 円
        <span ng-show="form.itemName.$error.required" class="invalid">必須項目です。入力してください</span><br>
        数量: <input type="number" name="qty" ng-model="qty" required> 個
        <span ng-show="form.itemName.$error.required" class="invalid">必須項目です。入力してください</span><br>
```

#全体のサンプルコード
いかがでしたでしょうか。
まずはなんとなく雰囲気が掴めたかと思います。
またAngularJSの強力なデータバインディング機能を実感していただけたかと思います。

以下は、本ページで解説したサンプルコードの完成形です。

```html:sample01.html
<!DOCTYPE html>
<title>Angular Sample 01</title>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<style>
    input.ng-invalid {
        background-color: #ffcccc;
    }
    .invalid {
        color: red;
    }
</style>
<div ng-app>
    <form name="form">
        <span ng-hide="form.$valid" class="invalid">未入力の項目があります</span><br>
        商品名: <input type="text" name="itemName" ng-model="itemName" required>
        <span ng-show="form.itemName.$error.required" class="invalid">必須項目です。入力してください</span><br>
        単価: <input type="number" name="price" ng-model="price" required> 円
        <span ng-show="form.itemName.$error.required" class="invalid">必須項目です。入力してください</span><br>
        数量: <input type="number" name="qty" ng-model="qty" required> 個
        <span ng-show="form.itemName.$error.required" class="invalid">必須項目です。入力してください</span><br>

        商品: {{itemName}}<br>
        合計: {{price * qty | number}} 円
    </form>
</div>
```

---
[目次](http://qiita.com/Koizumi-Greenwich/items/3e327e3331b2f728797e)
≫次の記事 2.[モジュール、コントローラー、サービス≪改訂≫](http://qiita.com/Koizumi-Greenwich/items/789276986bc3ff967eaa)

---