AngularJS 入門


AngularJSをとりあえず触ってみたい人向けの記事です。
面倒なので今回はYEOMANを使います。

## 準備するもの
YEOMANとAngularJS用のジェネレーター

```bash:
npm install -g yo
-npm install -g generator-angular
```

Compass（generator-angularが使っている）

```
gem install compass
```

## AngularJSのひな形を作成

適当にディレクトリを作って、そこで作業します。

YEOMANを使ってセットアップ（結構時間かかります）

```bash:
yo angular
[?] Would you like to include Twitter Bootstrap? Yes
[?] Would you like to use the SCSS version of Twitter Bootstrap with the Compass CSS Authoring Framework? Yes
[?] Which modules would you like to include? [Enter]
 ⬢ angular-resource.js
 ⬢ angular-cookies.js
 ⬢ angular-sanitize.js
 ⬢ angular-route.js
```

## さっそく動かしてみる

セットアップが完了したら表示してみます。

```bash:
grunt serve
```

![kobito.1386107090.356205.png](https://qiita-image-store.s3.amazonaws.com/0/30739/7601219b-7f49-3776-a984-144fd15d0d22.png "kobito.1386107090.356205.png")

表示されました。

__補足__
> Mac（OS X Mavericks）でnode.jsのバージョンが`0.10.17`の時に`grunt watch`タスクが`bus error`で動かなかったので、その時はnode.jsをアップデートしたら動くかもしれません。
> 私は`0.10.22`にアップデートして直りました。

この雛形では、ビューの読み込みしか行っていないので少し編集してAngularJSの部分に触れてみようと思います。

## AngularJSのバインディング（Hello World）

なぜこのファイルなのかは後々ルーティングの時に説明するので、とりあえずいろいろ編集してみます。

```html:app/views/main.html
<div class="header">
	<ul class="nav nav-pills pull-right">
		<li class="active"><a ng-href="#">Home</a></li>
		<li><a ng-href="#">About</a></li>
		<li><a ng-href="#">Contact</a></li>
	</ul>
	<h3 class="text-muted">angular sample</h3>
</div>
<div class="jumbotron">
	<p>Hello {{ world }}!</p> <!-- ここを追記 -->
</div>
```

このままでは`world`は空っぽなのでコントローラーから値を設定します。

```js:app/scripts/controllers/main.js
'use strict';

angular.module('angularSampleApp') // モジュール名はディレクトリ名によって変わるので注意
	.controller('MainCtrl', function ($scope) {

	 	$scope.world = 'Angular'; // ここを追記

	});
```

これで`Hello Angular!`と表示されるはずです。

![kobito.1386123015.940607.png](https://qiita-image-store.s3.amazonaws.com/0/30739/ce636c92-fbe7-24b6-1c03-7e42292d77f2.png "kobito.1386123015.940607.png")

なんとなくAngularJSの変数が分かると思います。

## AngularJSのバインディング ~ 配列編

配列の表示も簡単なのでついでにやります。
明らかにAngularJSっぽい`ng-init`や`ng-repeat`が出てきますが、今は __こう書けばこう動くんだー__ 程度の認識でよいです。

```html:app/views/main.html
<div class="header">
	<ul class="nav nav-pills pull-right">
		<li class="active"><a ng-href="#">Home</a></li>
		<li><a ng-href="#">About</a></li>
		<li><a ng-href="#">Contact</a></li>
	</ul>
	<h3 class="text-muted">angular sample</h3>
</div>

<div class="jumbotron">
	<p>Hello {{ world }}!</p>

	<!-- この下の部分を追記 -->
	<p ng-init="frameworks = ['Backbone.js', 'Ember.js', 'Knockout.js']">
		<h3>{{ frameworks.length }} frameworks</h3>
		<ul>
			<li ng-repeat="f in frameworks">{{f}}</li>
		</ul>
	</p>
</div>
```

* `ngInit`で変数の初期化
 > コントローラー内で `$scope.frameworks = ['Backbone.js', 'Ember.js', 'Knockout.js'];`と書くのと同義です。

* `ngRpeat`で変数をループしながらレンダリング

リストがちゃんと表示されていればOKです。

![kobito.1386125204.719984.png](https://qiita-image-store.s3.amazonaws.com/0/30739/60ae5f12-517f-ac57-f157-4cd46d122d47.png "kobito.1386125204.719984.png")


ここで１つ気づくのが `{{ frameworks.length }}` の部分です。
``{{}}``の中身は変数名から変数を取得するだけではなく、AngularJSによってコンパイルされます。

なので `{{ frameworks.length * 3 }}` のように計算させたり、`{{ frameworks.join(',') }}`のようにメソッドをコールする事も可能です。

次はリアルタイムに変更されるパターンをやってみます。
## ng-model ディレクティブ

AngularJSには処理や、DOMをひとまとめにしておく __ディレクティブ(Directive)__ という仕組みがあります。

その一つに、入力項目とAngularの変数をバインドさせる`ngModel`というディレクティブがあります。
> AngularJSのバインディング ~ 配列編 で使用している `ngInit`, `ngRpeat` もディレクティブです。

```html:app/views/main.html

```html:main.html
<div class="header">
<ul class="nav nav-pills pull-right">
	<li class="active"><a ng-href="#">Home</a></li>
	<li><a ng-href="#">About</a></li>
 	<li><a ng-href="#">Contact</a></li>
</ul>

<div class="jumbotron">
	<p><input type="text" ng-model="world"></p> <!-- この行を追加 -->
	<p>Hello {{ world }}!</p>

	<p ng-init="frameworks = ['Backbone.js', 'Ember.js', 'Knockout.js']">
		<h3>{{ frameworks.length }} frameworks</h3>
		<ul>
			<li ng-repeat="f in frameworks">{{f}}</li>
		</ul>
	</p>
</div>
```

たったこれだけでリアルタイムにビューに入力値が反映されるようになります。
すばらしいですねー

![kobito.1386125767.188347.png](https://qiita-image-store.s3.amazonaws.com/0/30739/334b19f1-c7e7-4e9a-a818-c217793a5a6b.png "kobito.1386125767.188347.png")


## UIイベントとの連携

* ボタンを押した時に処理を実行
* 処理結果をビューに反映

今からこの辺りを触ります。

#### まずボタンを追加

```html:app/views/main.html
<p>
	<input type="text" ng-model="world">
	<span ng-click="addFramework(world)" class="btn btn-primary">Add</span><!-- この行を追加 -->
</p>
<p>Hello {{ world }}!</p>

<p ng-init="frameworks = ['Backbone.js', 'Ember.js', 'Knockout.js']">
	<h3>{{ frameworks.length }} frameworks</h3>
	<ul>
		<li ng-repeat="f in frameworks">{{f}}</li>
	</ul>
</p>
```

#### `ng-click="addFramework(world)"` に対応する処理をコントローラーに追加

```js:app/scripts/controllers/main.js
'use strict';

angular.module('angularSampleApp')
	.controller('MainCtrl', function ($scope) {

		 $scope.world = 'Angular';

		 // この部分を追加
	 	$scope.addFramework = function (text) {
	 		$scope.frameworks.push(text);
			$scope.world = '';
		};

	});
```
書いた処理は以下だけ

* 渡されたテキストを配列に追加
* フォームにバインドされたテキストを空にする

> 補足
> `$scope.frameworks.push($scope.world)` と書けますが、今回は引数を受け取る事ができますという意味であえてこう書いてます。

ビューに結果を反映させるのは、変数に変更を加えればあとはAngularJSがうまい事やってくれるので特に気にしなくてもよいです。

![kobito.1386126646.227833.png](https://qiita-image-store.s3.amazonaws.com/0/30739/02af4ff3-49a8-b8e1-4101-f440ffedf32a.png "kobito.1386126646.227833.png")

これで動作するようになったと思います。

触りの部分は以上です