こんにちは。キャスレーコンサルティングSI(システム・インテグレーション)部のマルタンです。

今回は、Angular JSフレームワークについて記事を書かせていただきます。

Angular JS は、MVC(Model View Controller)Javascriptフレームワークです。

ModelとViewの間で、「ダブルデータバインディング」があります。
「ルーティング」でシングルページアプリケーションという、
一つのページで複数の画面の表示切り替えの機能を用いています。

下記チュートリアル(英語)を参考にして、サンプルAngularJSページを作りました。
https://www.airpair.com/angularjs/posts/angularjs-tutorial

今回の投稿では、まずAngularJSの概念を説明して、
このチュートリアルを例にした”Hello World”サンプルページの紹介、AngularJSフィルターの説明を行います。

概要

AngularJSでMVCのフロントエンドアプリを、下記の概念で作成できます。
MVC (Model-View-Controller)を構築するのに、下記のAngularJSコンポーネントを使います。

Model (データ:service(サービス), factory(ファクトリ))
View (AngularJSを活用するhtmlページ: directives(ディレクティブ) and filters(フィルター))
Controller (scope(スコープ), controller(コントローラー), contollerAs(コントローラー・アズ))

最小のデータバイディング例: “Hello World”ページ

controllerなしで、最小のソースコードを作ってみましょう。
まず、以下を見て「HelloWorld.html」と「HelloWorld.js」の2ファイルを作成してください。

Hello World ソース

HelloWorld.html

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Casley Consulting Angular tutorial </title>
<script src="http://code.angularjs.org/1.3.0-beta.17/angular.min.js"></script><!--➁-->
<script src="HelloWorld.js"></script>
</head>
<body ng-app="HelloWorldApp"><!--➃-->
<p> ここに変更してみると </p>
<input type="text" placeholder="ここに何か入力してください" ng-model="hello" ng-init="hello='Hello World'" /><!--➀-->
<p> ここに反映される : {{ hello }}</p><!--➀-->
<p> 上記メッセージは {{ hello.length }}<!--➀-->個の文字があります</p>
</body>
</html>

HelloWorld.js

angular.module("HelloWorldApp",[]);//➂

ソース解説

この小さなアプリは、下のテキストが上のテキストフィールドにバインディングがかかっているため、
テキストフィールドを編集した場合、下のテキストも自動的に変わります。

テキストフィールドのng-model属性で、「hello」というAngularの$scope変数を定義します。

下の段落では、同じ変数を使用して値を表示します。Angularの変数表示命令は下記になります。
{{ hello }}

同じ変数名で同じスコープ(➀)さえあれば、
値の変更をすると、Angularバインディングが使われている場所ならばどこでも変更が反映されます。

例えば、「hello.length」もフィールドに文字を入力するたびにすぐ更新されます。

上記のことをするためには、以下のことのみが必要です。
– Angular JSスクリプトのインクルード (➁)
– Javascriptでangularモジュールを定義 (➂)

ここでは、angularオブジェクトの「module()」というセッターを利用して
“HelloWorldApp”というモジュールを登録しています。

他の従属モジュールに基づいていないので、二つ目の引数(従属配列)は空の配列として”[]”を設定しています。

– ➃では、ng-app ディレクティブを使って、bodyタグでangularモジュールを使用するよう記述しています。

※bodyタグの代わりにdivタグも使えますが、
そのモジュールに関係あるものは、すべてそのdivタグの中に入れないとAngularで処理されません。

– “{{ }}”で変数を囲むことで、値を表示します。
– ng-initディレクティブで、イニシャライズすることができます。

※普段のイニシャライズされる変数は、コントローラのJavascriptの方で定義します(※次のソースを参照ください)。
イニシャライズされない変数は、htmlの方でng-model ディレクティブで定義します。

しかし、今回は変数をhtml内で値を”Hello World”としてイニシャライズしました。
初例でいきなりコントローラを使いたくなかったので、すべてhtml内でイニシャライズしましたが、
本格的にコードを書く場合はお勧めできません。

Angular JS コントローラとフィルター

Angularフィルターで、データの表示前のカスタム変更ができます。
例えば、フォーマット変換や配列の絞り込み条件、自作フィルターなどが使えます。
フィルターのAngularアプリケーションを、動かしてみる前にまずコントローラの勉強をしましょう。

Angular JS コントローラ

MVCでは、コントローラはモデルとビューの間の中央部分でモデルとビューの連携を行っています。
上記の例ですでに見た通り、この役割はAngularバインディングで一部出来ています。
他の間での処理が必要ならば、カスタムコントローラをJavascriptで記述しないといけません。

angular.module('app',[]).controller('myController', function(){/*ここにコントローラの処理を記述*/});

上記のようなインラインJavascriptに、慣れていない場合は下記のようにも書けます。

var app = angular.module('app',[]);
function myController(){
  /*ここにコントローラの処理を記述*/
}
app.controller('myController', myController);

そして、htmlファイルの方でコントローラを使うブロックを定義することが必要です。

<div ng-controller="myController">...</div>

コントローラスコープの変数(すなわちコントローラのJavascriptで定義された変数)を、表示する例は以下のとおりです。

Javascript

var app = angular.module('app',[]);
//$scope引数はAngular DI(Dependency Injection)で自動的に渡されている
function myController($scope){
  $scope.myvar = "Hello again";
}
app.controller('myController', myController);

HTML

<body ng-app="app">
  <div ng-controller="myController">
    myvar is {{myvar}}
  </div>
</body>

Angular JS フィルター

コントローラの勉強が終わったため、ようやくコントローラのデータにフィルターを与えられます。
フィルターは、下記のように記述して使用します。

HTML用

{{somethingToDisplay | filter名 : parameterObject }}

Javascript用

$filter('filter名')(somethingToDisplay, parameterObject)

以下、説明です。
– somethingToDisplay : 表示やフィルタリングをしたい変数、配列です。
– | filter名 : 「somethingToDisplay」に与えたいフィルター名の前に、パイプ字「|」があります。
– : paramterObject : 「:」と任意な引数オブジェクトです。
– $filter : 登録されたフィルターの配列オブジェクトです。

以下のように、DIでcontroller定義関数の引数に入れるだけで$filterが使えるようになります。

 function myController($scope, $filter)

Angularの存在しているフィルターは、「core filters」と言います。

例えば、下記ソースの「date」、「orderBy」、「uppercase」、「json」。

さらに、自作のフィルターも与えられます。さっそく様々な例を活用しましょう。

Filter ソース

下記ソースコードを、動かしてみてください。
Filter.html

<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
		<title>Casley Consulting Angular tutorial</title>
		<style>
			table, table td {
				border: 1px solid grey;
			}

		</style>
		<script src="http://code.angularjs.org/1.3.0-beta.17/angular.min.js"></script>
		<script src="Filter.js"></script>

	</head>
	<body ng-app="FilterApp">
		<div ng-controller="MainCtrl">
			<h1> Date Core filter </h1>
			<p>
				今日は
				{{ nowTime | date:'yyyy年MM月dd日'}}
				です
			</p>
			<hr/>
	        <h1> Various Filters </h1>
			<p>
				今回の配列をjsonフィルターでJSON系を表示しましょう :<br/>
				{{ employees | json}}
			</p>
	        <p>	配列にフィルターをかけましょう :</p>
	        <table>
	        	<tr><th>フィルター</th><th>書き方</th><th>結果</th></tr>
		        <tr><td>フィルターなし</td><td></td>
			        <td><ul>
				        	<li ng-repeat="employee in employees">
							{{ employee.name }} : {{ employee.department }}</li>
						</ul>
					</td>
				</tr>
				<tr><td>小文字 core filter</td><td> employee.department | lowercase</td>
			        <td><ul>
				        	<li ng-repeat="employee in employees">
							{{ employee.name }} : {{ employee.department | lowercase }}</li>
						</ul>
					</td>
				</tr>
				<tr><td>大文字 custom filter</td><td> employee.department | myUpperCase</td>
			        <td><ul>
				        	<li ng-repeat="employee in employees">
							{{ employee.name }} : {{ employee.department | myUpperCase }}</li>
						</ul>
					</td>
				</tr>
				<tr><td>部毎ソート配列 core filter</td><td>employee in employees | orderBy:'department'</td>
			        <td><ul>
				        	<li ng-repeat="employee in employees | orderBy:'department'">
							{{ employee.name }} : {{ employee.department }}</li>
						</ul>
					</td>
				</tr>
				<tr><td>「山」が入っている苗字 custom filter</td><td>employee in employees | myContains:{field:'name',lookupStr:'山'}</td>
			        <td><ul>
				        	<li ng-repeat="employee in employees | myContains:{field:'name',lookupStr:'山'}">
							{{ employee.name }} : {{ employee.department }}</li>
						</ul>
					</td>
				</tr>
				<tr><td>フィルター合わせ:<ul><li>小文字 core filter</li><li>大文字 カスタム filter</li><li>部毎ソート配列 core filter</li></ul></td>
					<td><ul><li>employee in employees | orderBy:'department'</li><li> employee.department | lowercase | myUpperCase </li></ul></td></td>
			        <td><ul>
				        	<li ng-repeat="employee in employees | orderBy:'department'">
							{{ employee.name }} : {{ employee.department | lowercase | myUpperCase }}</li>
						</ul>
					</td>
				</tr>

			</table>

	    </div>
	</body>
</html>

Filter.js

// アプリケーションモジュールを定義(setter)。getterの「angular.module("FilterApp")」が使えるように下記セッターが必須です
angular.module("FilterApp",[]);

// Controller定義。Dependency  Injectionで「$scope」がAngularから渡されています
function MainCtrl ($scope) {
	// 新しいスコープ変数で今日の日付をスコープに入れます
	$scope.nowTime = new Date().getTime();

	// 配列の定義
		$scope.employees = [
		{
			department:"SC事業部",
			name:"佐藤"
		},
		{
			department:"SD事業部",
			name:"鈴木"
		},
		{
			department:"HRS部",
			name:"高橋"
		},
		{
			department:"企画部",
			name:"田中"
		},
		{
			department:"経営管理部",
			name:"伊藤"
		}
	];
}

// アプリケーションにコントローラーを登録する
angular.module("FilterApp").controller("MainCtrl", MainCtrl);

// カスタムフィルタの定義。アイテム引数を大文字に変更します。Angularの存在しているuppercaseフィルターを使いましょう。
// $filterはDIで渡されています。これで存在しているAngularフィルターとカスタムフィルターはJavascriptからでも使えます
function myUpperCase ($filter) {
	return function(item) {
		return $filter('uppercase')(item);
	}
}

// アプリケーションにフィルターを登録する
angular.module("FilterApp").filter("myUpperCase", myUpperCase);

// カスタムフィルターの定義。ある配列のある要素のプロパティがある値を含めていたら返されます。なかったらフィルタリングされます
function myContains () {
	return function(items, param) {
		return items.filter(function(item) {
			// field: フィルタリングが行われるプロパティ名. lookupStr : フィルタリングの値. この値がプロパティに入っていないとフィルタリングされます
			return (item[param.field].indexOf(param.lookupStr) > -1 );
		});
	};
}

// アプリケーションにフィルターを登録する
angular.module("FilterApp").filter("myContains", myContains);

ソースコードのコメントだけでもお分かりになると思いますが、下記も参考ください。
– 「ng-repeat」ディレクティブであるタグとその内容を、各配列の要素を使って繰り返せます。

<li ng-repeat="employee in employees">{{ employee.name }} : {{ employee.department }}</li>

– カスタムフィルターの定義時に、コアフィルターが使えます。「myUpperCase」を参照。
– 注意:今回のフィルターの中で、一部がng-repeatの実行前に配列の絞り込みで使われていて、
 一部が繰り返しで要素に与えられています。
– 「lowercase」と「myUpperCase」を両方とも与えると、最後のフィルターの結果は大文字になります。

以上です。Angularはいかがでしたか?