Contenu connexe
Similaire à AngularJS入門 (20)
Plus de Kenji Shirane (7)
AngularJS入門
- 3. Obserever パターンと UI 設計
• Observer パターン
– Observer: Subject の変更を監視し、変更時に表示を更新する
– Subject: データを保持し、Observer の登録・削除メソッドを持つ
• Model-View
– UI 設計に Observer パターンを適用
• 表示機能(View)と表示対象データ(Model)とに分割し、
• 0 個以上の View が Model を observe する構造で UI を構成する
view1
modelview2
view3
Observer Subject
+notify()
+notifyObserves()
+addObserver()
+deleteObserver()
*
①Model を操作
(データの変更発生)
②Model は変更したことを View に通知する
③View は Model から変更後のデータを取得して表示更新
- 4. MVC パターン
• MVC パターン
– Model(ビジネスロジック)、View(ユーザーインターフェイス)、
Controller(Model と View の仲立ち)の3つの責務に基づいて
アプリケーションを構成する設計パターン
要素 責務(役割)
Model(モデル) アプリケーションが扱うデータの管理と操作を受け持つ。
データを操作するための機能(ビジネスロジック)を提供する。
View(ビュー) ユーザーインターフェイスに対応する部分。
ユーザーからの入力受付と結果の表示を担当する。
Controller(コントローラ) Model と View の両方に関連を持ち、処理の流れを制御す
る役割を受け持つ。View から受け取ったデータを Model に
渡し、表示の更新が必要な Model の変更を View に通知
する。
- 5. (参考)Model2(MVC2)
• Model2
– MVC をサーブレット/JSP 等の Web システム構造に適用したもの
• JSP 仕様のドラフトにおいて提唱された(1998年)
– 実質的な UI であるブラウザにモデルの変更が通知される仕組みはない
(Observer パターンになっていない)
Controller
View
Model転送
操作
参照
ブラウザ
要求
応答
- 7. MVVM:Model-View-ViewModel
• MVVM:MVC の派生パターン
– View
• ユーザーからの入出力操作を
受け付ける UI
– ViewModel
• 表示用の状態データ
– View と同期(データバインディング)
• View からの入力を
Model に反映させる役割
– Model
• アプリケーション固有の部分
– ビジネスロジック
– データ
View
ViewModel
Model
ユーザー操作
データバインディング
ユーザー
インターフェイス
表示用データ
ビジネスロジック
データ
操作 取得
- 8. JavaScript MVC/MVVM フレームワーク
• AngularJS
– フルスタックの JavaScript MVC フレームワーク
• React
– Facebook によるフレームーワーク。View の機能を提供する。
• Backbone.js
– シンプルな構造が特徴のフレームワーク。
• Knockout.js
– ASP.NET SPA アプリに標準対応したフレームワーク
• Ember.js
– フルスタックのフレームワーク
- 9. AngularJS とは
• AngularJS とは
– JavaScript によるアプリケーション フレームワーク
– MVC に基づくクライアントアプリケーション開発をサポート
– 入手先
• https://angularjs.org/
• 特徴
– Google を中心に開発されている
– ドキュメント/関連ライブラリの充実
– フルスタック
• MVC 構造のほか
アプリ開発に必要な種々の機能
- 12. AngularJS の中核機能
• テンプレート
– ディレクティブ
– AngularJS 式
– データバインディング
• View-ViewModel
– 反復表示
• ng-repeat
– フィルタ
• MVC
– Controller
– テンプレートとの関連付け
– サービス
• ビジネスロジックの分離
– 依存性注入
• Dependency Injection
– ルーティング
- 13. ステップ1:テンプレートとディレクティブ
• テンプレート
– MVC の View となるページを記述する
• HTML の拡張構文を利用する
• AngularJS の HTML 構文拡張
– AngularJS 式: {{ <式> }}
• AngularJS の処理系が式を評価し、その結果に変換される
– ディレクティブ
• DOM 要素(属性、HTML タグ名、コメント、CSS クラス)のマーカー
• 指定した DOM 要素に特定の振る舞いを関連付ける働きを持つ
• 双方向データバインディング
– テンプレートの要素と表示用データを相互に同期させる仕組み
• MVVM における View と ViewModel の関係
Intro of
this step
- 14. サンプル:テンプレート HTML
• ajs00_template.html
– テンプレート出発点:AngularJS 適用前の普通の HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>サンプル00</title>
</head>
<body>
<h1>3 + 4</h1>
</body>
</html>
- 15. サンプル:AngularJS 式
• ajs01_expression.html
– AngularJS 式で 「3+4」 を評価させる例
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="UTF-8" />
<title>サンプル01</title>
<script src="angular.min.js"></script>
</head>
<body>
<h1>{{3 + 4}}</h1>
</body>
</html>
ng-app ディレクティブ
AngularJS を初期化し、処理対象のルート要素を指定する
AngularJS 式:{{ ~ }}
AngularJS による評価結果が表示される式
- 16. サンプル:双方向データバインディング
• ajs02_databinding.html
– 双方向バインディングの例
• ng-model ディレクティブを指定した input 要素と変数 name との間で
データバインディングをする例
<!DOCTYPE html>
<html ng-app>
<head>~</head>
<body>
名前:
<input type="text" ng-model="name" /> {{name}}
</body>
</html>
ng-model ディレクティブ
input、select、textarea の各要素を
変数(=スコープのプロパティ:後述)にバインドする。
変数が存在しない場合は新たに定義される。
ng-model でバインドした変数の評価式:
input タグの入力値が自動的に反映される。
name 変数が変更されると逆に input 要素が更新される
- 17. ステップ1:ポイントまとめ
• テンプレート
– 拡張版の HTML でテンプレートを記述する
• AngularJS がテンプレートを読み込んで処理した結果が表示される
• AngularJS 式:{{ }}
– {{ と }} で囲んで記述した式のこと
• 式を評価した結果が表示される
• ディレクティブ
– DOM 要素に特定の振る舞いを関連付けるマーカー
• ng-app ディレクティブ
– AngularJS の初期化と処理対象のルート要素を指定する
• ng-model ディレクティブ
– input、select、textarea の各要素と変数をバインドして相互に値を同期させる
- 21. サンプル:in の後を変数に置換
• ajs05_repeat3.html
– in の後にリテラルではなく変数を配置する例
<!DOCTYPE html>
<html ng-app>
<head>~</head>
<body ng-init="obj={name:'太郎',age:25,address:'札幌'}">
<ul>
<li ng-repeat="(k, v) in obj">
{{k}}の値 = {{v}}
</li>
</ul>
</body>
</html>
変数 obj へのオブジェクトリテラルの代入式を
ng-init ディレクティブで評価(実行)する
上記の代入式で初期化された変数 obj を
反復処理の対象オブジェクトとして指定している
- 22. ステップ2:ポイントまとめ
• ng-repeat ディレクティブ
– 配列の要素を順次取得して反復処理を行う
• 例)<div ng-repeat="member in group">~</div>
– group:集合
– member:集合の要素が順次代入される変数
– オブジェクトのプロパティを順次取得して反復処理を行う
• 例)<div ng-repeat="(key, value) in object">~</div>
– key:オブジェクトのプロパティ名
– value:プロパティの値
– objcet:プロパティを取り出す対象のオブジェクト
※1)いずれも ~ の部分で {{ }} 式を用いて要素やプロパティの値を出力できる
※2)特別に予約された変数 $index で処理中の要素のインデックスを取得できる
• ng-init ディレクティブ
– 代入式などの式を現在のスコープ内で評価(実行)する
- 23. ステップ3:フィルタ
• フィルタとは
– 式の値を通過させることで、
• 書式の設定
• 値の変換
• 条件に該当しないものの除外
• 並べ替え
・・・
など変更を加えた結果を取得する機能
– 表記法
• パイプ記号(|)で作用させる
– {{ 式 | フィルタ1 | フィルタ2 | フィルタ3 }}
• コロン (:) でフィルタに引数を渡すこともできる
– {{ 式 | フィルタ:引数1:引数2 }}
Intro of
this step
フィルタ1
フィルタ2
フィルタ3
表示出力
式
- 24. サンプル:orderBy で並べ替え
• ajs06_orderby.html
– orderBy フィルタで並べ替えする例
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="UTF-8" />
<title>サンプル06</title>
<script src="angular.min.js"></script>
</head>
<body ng-init="words = ['プリン','プリンタ','プロバイダ','プロフェッショナル','プール']">
<ul>
<li ng-repeat="word in words | orderBy : word : false">
{{word}}
</li>
</ul>
</body>
</html>
orderBy フィルタは集合の並べ替えを行う。
第1引数が並べ替え基準のプロパティ名(この場合は変数自体)
第2引数は降順にするかどうかの Bool 値 (true なら降順)
- 25. サンプル:フィルタによる絞り込み
• ajs07_filter.html
– 配列を filter フィルタで絞り込んだ結果を反復処理する例
<!DOCTYPE html>
<html ng-app>
<head>~</head>
<body ng-init="words = ['プリン','プリンタ','プロバイダ','プロフェッショナル','プール']">
<ul>
<li ng-repeat="word in words | filter:'プロ'">
{{word}}
</li>
</ul>
</body>
</html>
filter フィルタは、引数で指定された文字列を
含むものだけを抽出するフィルタ。
この例では、'プロ' という文字列が含まれるもの
だけが表示される。
- 26. サンプル:絞り込み条件をバインド
• ajs08_bindfilter.html
– データバインドした変数をフィルタの条件に指定する例
<!DOCTYPE html>
<html ng-app>
<head>~</head>
<body ng-init="words = ['プリン','プリンタ','プロバイダ','プロフェッショナル','プール']">
<input type="text" ng-model="name" />
<ul>
<li ng-repeat="word in words | filter:name">
{{word}}
</li>
</ul>
</body>
</html>
input 要素のボックスに入力された文字列に
データバインディングした name 変数を
フィルタの条件として引数に指定している。
input 要素の入力と name 変数は同期する
ので入力に応じて動的に一覧が絞り込まれる
- 27. ステップ3:ポイントまとめ
• フィルタとは
– 式の値を表示する書式を設定できるようにする機能
– 式の右側にパイプ記号(|)で区切って並べることで作用させる:
• {{ expression | filter }}
– 式 expression に filter を作用させる例
– フィルタの出力に別のフィルタを作用させることもできる:
• {{ expression | filter1 | filter2 }}
– 式 expression に filter1 を作用させた出力に filter2 を作用させる例
– フィルタは引数を受け取ることができる:
• {{ expression | filter:arg1:arg2・・・ }}
– 第1引数に arg1、第2引数に arg2 を受け取るフィルタの使用例
– フィルタの例
• filter フィルタ:引数に指定した文字列を含むものだけを抽出する
• orderBy フィルタ:引数に指定した項目に基づいて並べ替えを行う
- 28. ステップ4:コントローラとスコープ (1)
• AngularJS による UI
– 画面要素は拡張 HTML で記述する = テンプレート
– UI に関するロジックはどこに書く?
• コントローラ
– AngularJS の UI 関連ロジックを記述する場所
• コントローラ オブジェクトのコンストラクタとして定義する(後述)
• =MVC の Controller:View や Model と連携して処理を制御する部分
– コントローラは View(テンプレート)とどうやって連携するのか?
View Controller
テンプレート(HTML) JavaScript
- 29. ステップ4:コントローラとスコープ (2)
• スコープ:テンプレートとコントローラの仲介役
– コントローラのコンストラクタに引数 $scope として渡される
• テンプレートとコントローラの両方からアクセスできるオブジェクト
– コントローラ側:
$scope のプロパティとして変数や関数を設定する
– テンプレート (View) 側:
ng-controller ディレクティブで特定のコントローラを要素に指定すると、
そのコントローラに対応する $scope の各プロパティに、
単独のプロパティ名や関数名でアクセスできる。
View Controller$scope
テンプレート(HTML) JavaScript
スコープ
{{name}}
ng-click="myfunc()"
$scope.name = ・・・;
$scope.myfunc =
function() {・・・};
name myfunc
プロパティ / メソッド
- 30. サンプル:コントローラで配列を定義
• ajs09_controller.html
– ng-init ではなく、コントローラで配列を定義する例
<!DOCTYPE html>
<html ng-app="myapp">
<head>~</head>
<body ng-controller="MyController">
<input type="text" ng-model="name" />
<ul>
<li ng-repeat="word in words | filter:name">
{{word}}
</li>
</ul>
<script>
angular.module("myapp", [])
.controller("MyController", function ($scope) {
$scope.words = ['プリン', 'プリンタ', 'プロバイダ', 'プロフェッショナル', 'プール'];
});
</script>
</body>
</html>
angular.module() API でモジュール(後述)を作り、
その controller() メソッドにコントロール名とコンストラクタ
関数を渡してコントローラを定義する。
コントローラのスコープを有効にする範囲のルート要素に
ng-controller ディレクティブでコントローラ名を指定
- 31. サンプル:コントローラでメソッドを定義
• ajs10_ctrlmethod.html
– $scope に設定したメソッドをテンプレート側のクリックハンドラとして設定する例
<!DOCTYPE html>
<html ng-app="myapp">
<head>~</head>
<body ng-controller="MyController">
<button ng-click="myfunc()">呼び出しテスト</button>
<script>
angular.module("myapp", [])
.controller("MyController", function ($scope) {
$scope.myfunc = function () {
alert("myfunc: 呼び出されました");
};
});
</script>
</body>
</html>
ng-click ディレクティブで、クリックされたときの応答を設
定している。この例では myfunc() 関数が呼び出される。
コントローラ側では $scope のプロパティ
myfunc として関数を設定している。
- 32. サンプル:複数のコントローラを定義する
• ajs11_multictrl.html
– 2つのコントローラを登録して同じ名前で異なる実装の関数をスコープに設定する例
~
<body>
<div ng-controller="MyController1">
<button ng-click="myfunc()">呼び出しテスト1</button>
</div>
<div ng-controller="MyController2">
<button ng-click="myfunc()">呼び出しテスト2</button>
</div>
<script>
angular.module("myapp", [])
.controller("MyController1", function ($scope) {
$scope.myfunc = function () {
alert("myfunc: コントローラ1で呼び出されました");
};
})
.controller("MyController2", function ($scope) {
$scope.myfunc = function () {
alert("myfunc: コントローラ2で呼び出されました");
};
});
</script>
</body>
~
MyController1 のスコープで
myfunc を呼び出す
MyController2 のスコープで
myfunc を呼び出す
controller メソッドの戻り値が
元のモジュールになっているので、
ピリオド . で連結して繰り返し
呼び出すことができる
(メソッドチェーン)
- 33. ステップ4:まとめ
• コントローラ
– AngularJS の UI 関連ロジックを記述する場所
• モジュールの controller メソッドで登録する
– 第1引数:コントローラ名
– 第2引数:コンストラクタ関数を指定する
– テンプレート (HTML) とのデータ交換
• コンストラクタに渡される $scope という名前の引数を通じて行う
– テンプレートとコントローラの両方からアクセスできるオブジェクト
• 使い方
– コントローラ側
• テンプレートと共有する変数や関数を $scope 変数のプロパティとして設定する
– テンプレート側
• コントローラを関連づける範囲のルート要素に
ng-controller ディレクティブでコントローラの名前を指定する
– ng-controller ディレクティブがスコープの有効範囲を定義する
• そのコントローラの $scope のプロパティが、ルート配下で変数や関数としてアクセスできる
- 34. ステップ5:モジュールとサービス
• モジュールとは
– AngularJS アプリケーションの構成要素を束ねるコンテナ
• コントローラ、フィルタ、ディレクティブ、サービス・・・
– angular.module() API で作成する
• 第1引数:モジュール名
• 第2引数:依存する別のモジュール名の配列
– ng-app ディレクティブに指定することで有効になる
• アプリケーションのルート モジュールとなる
ディレクティブフィルタ サービス コントローラ ・・・
モジュール
- 35. 前出のサンプルでモジュールの部分を確認
• ajs10_ctrlmethod.html
– myapp という名前でアプリケーションのルートモジュールを作成して初期化する例
<!DOCTYPE html>
<html ng-app="myapp">
<head>~</head>
<body ng-controller="MyController">
<button ng-click="myfunc()">呼び出しテスト</button>
<script>
angular.module("myapp", [])
.controller("MyController", function ($scope) {
$scope.myfunc = function () {
alert("myfunc: 呼び出されました");
};
});
</script>
</body>
</html>
第1引数:モジュールの名前
ここでは myapp という名前を指定
第2引数:依存先のモジュール名の配列
この例では依存モジュールはないので空の配列
ng-app ディレクティブに
アプリケーションのモジュール名を指定
- 36. サービスについて
• サービスとは
– アプリケーションの中で特定のタスクを担当するコンポーネント
• ライブラリで用意しているもの(例:$http サービス)
• 自作するもの
• 依存性注入(DI = Dependency Injection)
– あるオブジェクトが動作するのに必要なコンポーネントを外部から組み込む仕組み
– AngularJS は注入するサービスを引数の名前で決定する
• 例)$scope という名前を引数に指定するとスコープオブジェクトが自動的に渡される
– 変数名を変えるとスコープとして機能しなくなる
サービスの
コンポーネント
AngularJS がサービス コンポーネントのインスタンスを生成して注入する
生成注入
- 37. サンプル:$http サービスの利用
• $http サービスを利用して GET リクエストを発行する例
~
<body ng-controller="MyController">
<button ng-click="myfunc()">$httpテスト</button>
<input type="text" ng-model="result" />
<script>
angular.module('myapp', [])
.controller('MyController', function ($scope, $http) {
$scope.myfunc = function () {
$http({
method: 'GET', url: 'ajs12.txt'
})
.success(function (data, status, headers, config) {
$scope.result = data;
})
.error(function (data, status, headers, config) {
$scope.result = 'エラー';
});
};
});
</script>
</body>
~
ajs12_modhttp.html
この引数を通じて $http サービスの
インスタンスが注入される
テキストボックスの入力値と
$scope.result をデータバインド
ajs12.txt の内容が
読み込まれる
- 38. 非同期通信:$http サービス (1)
• $http サービス
– XMLHttpRequest(XHR)オブジェクトのラッパー
– $http() 関数の呼び出しで非同期の HTTP リクエストを送信する
– この関数の返却値にコールバックを設定できる:
• then(<成功時コールバック>, <エラー時コールバック>)
– 成功時と失敗時の両方をまとめて指定する
• success(<コールバック関数>) メソッド
– 通信成功時(HTTP ステータス 200)に呼び出されるコールバック関数を指定する
• error(<コールバック関数>) メソッド
– 通信失敗時(ステータス 200以外)に呼び出されるコールバック関数を指定する
▼$http サービス
$http({パラメータ:値,パラメータ:値,・・・})
・パラメータ:非同期通信のパラメータ名
・値:パラメータに対応する指定値
- 39. 非同期通信:$http サービス (2)
• $http の引数に渡すオブジェクトのパラメータ仕様
– https://docs.angularjs.org/api/ng/service/$http
• コールバック関数の引数
パラメータ名 説明
method 送信するリクエストの HTTP メソッド名を文字列で指定する
url リクエストの送信先 URL
params クエリパラメータのハッシュ形式(キー:値, ・・・)
data 送信するデータのハッシュ形式(キー:値, ・・・)
headers リクエスヘッダーのハッシュ形式(キー:値, ・・・)
パラメータ名 説明
data レスポンスの本文(JSONの場合は変換後のオブジェクト)
status HTTPステータスコード
headers レスポンスヘッダー
config リクエスト発行時に渡された構成オブジェクト
- 40. サービスの自作
• ビジネスロジックの分離
– ビジネスロジックは独立したサービス コンポーネントに分離する
– サービスを分離するメリット
• 一つのサービスを複数のコントローラで共有できる
• コントローラは制御に徹することができ見通しを立てやすい
• ビジネスロジック単体でのテストがしやすくなる
– モジュールのメソッドで定義する
• value(name, object)
– object: 文字列、数値、配列、オブジェクト、関数
• service(name, constructor)
– constructor: 共有するオブジェクトのコンストラクタ関数
• factory(name, func)
– func: 共有するオブジェクトを返却する関数
- 41. サンプル:value メソッドで値の共有
• value メソッドで共有文字列を指定する例
– ajs13_modvalue.html
~
<script>
angular.module("myapp", [])
.controller("MyController1", function ($scope, CommonValue) {
$scope.myfunc = function () {
alert("コントローラ1:" + CommonValue);
};
})
.controller("MyController2", function ($scope, CommonValue) {
$scope.myfunc = function () {
alert("コントローラ2:" + CommonValue);
};
})
.value('CommonValue', 'hogege');
</script>
</body>
</html>
この引数を通じて $http サービスの
インスタンスが注入される
第1引数に文字列として指定した名前で
第2引数の値(この例では文字列)をサービスとして登録する。
異なるコントローラから
同じ値を参照できる
- 42. サンプル:service メソッドで値の共有 (1)
• service メソッドで共有オブジェクトのコンストラクタを指定する例
– ajs14_modservice.html
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<meta charset="UTF-8" />
<title>サンプル14</title>
<script src="angular.min.js"></script>
</head>
<body ng-controller="MyController">
<button ng-click="myfunc()">リクエスト送信</button>
<script>
angular.module("myapp", [])
.controller("MyController", function ($scope, MyModel) {
$scope.myfunc = function () {
MyModel.sendRequest();
};
})
~
MyModel サービスの
インスタンスが注入される
インスタンスのメソッドを呼び出す
- 43. サンプル:service メソッドで値の共有 (2)
<script>
angular.module("myapp", [])
.controller("MyController", function ($scope, MyModel) {
$scope.myfunc = function () {
MyModel.sendRequest();
};
})
.service('MyModel', function ($http) {
this.sendRequest = function () {
$http({
method: 'GET',
url: 'ajs12.txt'
})
.success(function (data, status, headers, config) {
alert("success: " + data);
})
.error(function (data, status, headers, config) {
alert("error: " + data);
});
};
});
</script>
~
service メソッドでは、第2引数に
サービスのコンストラクタ関数を指定する
service で作成するサービスでは、
$http 等の別のサービスを注入できる。
(value メソッドの場合は不可)
$http サービスを注入することで
通信処理をモデル側に移動している
- 44. サンプル:factory メソッドで書き換える
• factory メソッドで先の MyModel を書き換える例
– ajs15_modfactory.html
angular.module("myapp", [])
.controller("MyController", function ($scope, MyModel) {
$scope.myfunc = function () {
MyModel.sendRequest();
};
})
.factory('MyModel', function ($http) {
return {
sendRequest: function () {
$http({
method: 'GET',
url: 'ajs12.txt'
})
.success(function (data, status, headers, config) {
alert("success: " + data);
})
.error(function (data, status, headers, config) {
alert("error: " + data);
});
}
};
});
factory メソッドの場合は、
コンポーネントのコンストラクタではなく、
そのコンポーネントを返却する関数を指定する。
既存コンポーネントの場合は、
単にそのインスタンスを返却すればよい
(そのような場合に便利なメソッド)
- 45. ステップ5:まとめ
• モジュール
– AngularJS アプリケーションの構成要素を束ねるコンテナ
– angular.module() API で作成する
• 第1引数:モジュール名
• 第2引数:依存する別のモジュール名の配列
– ng-app ディレクティブにモジュール名を指定すると使用可能になる
• サービス
– 特定のビジネスロジックを独立したコンポーネントとして分離したもの
– サービス定義用のメソッドがモジュールに用意されている:
• value(name, object) シンプルな値に名前をつけてサービスとして共有
• service(name, constructor) 指定したコンストラクタで生成されるオブジェクトを共有
• factory(name, func) 指定した関数が返却するオブジェクトを共有
– 依存性注入(DI)
• サービスのコンポーネントのインスタンス生成と組み込みを自動的に行う仕組み
• 関数の引数名をサービス名にすることで対応するインスタンスが自動的に生成されて渡される
- 46. ステップ6:ルーティング
• ルーティングとは
– リクエストの URL に応じてコントローラとテンプレートを振り分けること
• 特定のパス(のパターン)と、コントローラ/テンプレートを関連づける
– これにより、遷移ページごとに異なるテンプレートとコントローラを指定できる
コントローラ コントローラ コントローラ
テンプレート テンプレート テンプレート
AngularJS アプリケーション
$routeProvider
URLパターン コントローラ テンプレート
/ MainController main.html
/about AboutController about.html
・・・
リクエスト
パスを指定する
$routeProvider が登録された対照表に基づき
リクエストを適切なコントローラ/テンプレートに割り振る
- 47. サンプル:ルーティングによるページ遷移 (1)
• ファイル構成(ajs16 フォルダ内)
– テンプレートファイル
• index.html アプリケーションの入り口となるファイル
• main.html 相対パス ~/ に対応する内容のテンプレート
• about.html 相対パス ~/about に対応する内容のテンプレート
• guide.html 相対パス ~/guide に対応する内容のテンプレート
– JavaScript ファイル
• myapp.js
– これまでテンプレート内に直接記述していたコードを別ファイルに分離
– angular.min.js と angular-route.min.js を先に読み込むことが前提
- 48. サンプル:ルーティングによるページ遷移 (2)
• index.html
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<meta charset="UTF-8" />
<title>サンプル16</title>
</head>
<body>
<div class="header">
<a href="#/">Main</a> |
<a href="#/about">About</a> |
<a href="#/guide">Guide</a>
</div>
<hr/>
<div class="content" ng-view></div>
<hr/>
<div class="footer">サンプル16</div>
<script src="angular.min.js"></script>
<script src="angular-route.min.js"></script>
<script src="myapp.js"></script>
</body>
</html>
ng-view ディレクティブを指定した要素の配下に
パスに対応するコンテンツが埋め込まれる。
各遷移先の URL は、リンク元のページの
URL に # で区切ってパスを連結した形になる
- 49. サンプル:ルーティングによるページ遷移 (3)
• myapp.js
angular.module("myapp", ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/', { templateUrl: 'main.html', controller: 'MainController' })
.when('/about', { templateUrl: 'about.html', controller: 'AboutController' })
.when('/guide', { templateUrl: 'guide.html', controller: 'GuideController' })
.otherwise({
redirectTo: '/'
})
})
.controller('MainController', function ($scope) {
$scope.content = 'main のコンテンツ';
})
.controller('AboutController', function ($scope) {
$scope.content = 'about のコンテンツ';
})
.controller('GuideController', function ($scope) {
$scope.content = 'guide のコンテンツ';
});
$routeProvider の when メソッドを利用して
パスとコントローラ/テンプレートを対応付けしている。
第1引数:パス
第2引数:テンプレートとコントローラを指定する連想配列
otherwise メソッドは、いずれも該当しない場合の処理を定義する。
redirectTo は指定したパスにリダイレクトさせる指定。
ルーティング機能は AngularJS のコアではなく
ngRoute モジュールなので依存先に指定する
- 51. ステップ6:まとめ
• ルーティングの設定
– ngRoute という非コアモジュールを利用する:
• angular-route.min.js ファイルをインポートし、
• モジュールの依存先モジュール(第2引数の配列)に 'ngRoute' を指定する
• $routeProvider を利用してパスとコントローラ/テンプレートを関連づける
– $routeProvider は DI で注入される
– 下記メソッドを利用してパスとコンテンツを関連づける
» when('<パス>', <連想配列>) パスごとの指定
» otherwise いずれのも該当しない場合の指定
• 連想配列の形式:{templateUrl:~, controller:~}
– config() メソッドで行う
• ルーティング設定はモジュールの config() メソッドに渡す関数の中で行う
– 出力先に ng-view ディレクティブ
• 各パスに対応するコンテンツは ng-view を指定した要素の下に出力される
- 52. ステップ7:フォーム
• AngularJS のフォーム拡張
– HTML のフォームやコンポーネントの要素も拡張が加えられている
– 拡張の例)
• form 要素の拡張属性
– name フォームの名前(検証で使用)
– ng-submit submit 時に呼び出す処理
– novalidate HTML5 の検証処理を無効化する
• input、textarea 要素の拡張属性(一部)
– ng-model 入力値とデータバインドする変数名
– name 要素の名前
– ng-change 入力値に変更があったときに呼び出す処理
– ng-required 必須かどうかを指定する
• select 要素の拡張属性
– ng-options 集合データからオプション要素を展開する
- 53. サンプル:select の使用例 (1)
• myapp_select.js
– コントローラ側で商品情報オブジェクトの配列をスコープにセットする
angular.module("myapp", [])
.controller('MyController', function ($scope) {
$scope.products = [
{ pid: 101, name: '鉛筆パック', price: 350 },
{ pid: 102, name: 'オフィスデスク', price: 35000 },
{ pid: 103, name: 'コピー用紙', price: 580 }
];
})
- 54. サンプル:select の使用例 (2)
• ajs17_select1.html
– 配列要素のオブジェクトの name プロパティをオプションとして表示する例
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<meta charset="UTF-8" />
<title>サンプル17</title>
</head>
<body ng-controller="MyController">
<div>
<select id="pname" name="pname" ng-model="pname"
ng-options="prdct.name for prdct in products">
<option value="">(選択)</option>
</select>
</div>
<script src="angular.min.js"></script>
<script src="myapp_select.js"></script>
</body>
</html>
スコープ内の products 配列の要素を
prdct という変数で表して反復処理する例
for と in の使い方を確認してください。
別ファイルに分けたコントローラをインポート
- 55. サンプル:選択値を別個に指定する例
• ajs18_select2.html
– 選択値を表示値とは違うプロパティ(pid)に指定し、選択値を表示する例
<!DOCTYPE html>
<html ng-app="myapp">
<head>~</head>
<body ng-controller="MyController">
<div>
<select id="pname" name="pname" ng-model="selected"
ng-options="prdct.pid as prdct.name for prdct in products">
<option value="">(選択)</option>
</select>
<span>選択値:{{selected}}</span>
</div>
<script src="angular.min.js"></script>
<script src="myapp_select.js"></script>
</body>
</html>
スコープ内の products 配列の要素を
prdct という変数で表して反復処理する例
for と in の使い方を確認してください。
- 56. (参考)API とドキュメントについて
• AngularJS の API について
– AngularJSで提供される種々の機能の詳細は、
Webで公開されている API ドキュメント(英語)で調べることができる:
• https://docs.angularjs.org/api
• ドキュメント調査のヒント
– ディレクティブ
• テンプレート(HTMLファイル)で利用できるAngularJSの命令で、タグや属性として指定する。
• ディレクティブには複数の表記法がありいずれの異なる表記法で記述しても機能としては等価:
内部的には、先頭から「x-」「data-」を削除し、「:」「-」「_」で区切られた名前をキャメルケース
(camelCase)にすることで表記法を統一できる。ドキュメントではこの表記法が使われている。
• 各ディレクティブに説明とサンプルコードが提供されており、具体的な使い方を確認できる。
– フィルタ
• テンプレート上に埋め込まれたデータの書式を設定するための仕組み
– サービス
• アプリケーション開発に役立つ機能を提供する。
• 依存性注入を利用してサービスをインスタンス化して注入することで利用できる。
- 57. (参考)配列アノテーションによる DI
• ソース圧縮による引数名変更の問題
– ソース圧縮(ミニフィケーション)で引数名が変更される可能性がある
• $scope という引数名を目印にインジェクションが行われるため、
この名前が変更されるとコードが動作しなくなる
• 識別名 $scope の変更を防ぐには文字列として処理系に伝える方法が必要
• 対策:配列アノテーション
– 配列要素として、引数名の文字列と関数を指定する方法
• 従来の方法
.controller('CtrlName',function($scope){・・・});
• 配列アノテーション
.controller('CtrlName',['$scope',function($scope){・・・}]);
– DI に必要な引数名を文字列の配列要素として設定する
– 複数ある場合は引数の順に設定する
- 58. サンプル:ajs12_modhttpX.html
• $scope と $http の使用例に配列アノテーションを適用すると・・・
– ajs12_modhttpX.html
<script>
angular.module('myapp', [])
.controller('MyController',
['$scope', '$http', function($scope, $http) {
$scope.myfunc = function () {
$http({
method: 'GET',
url: 'ajs12.txt'
})
.success(function (data, status, headers, config) {
$scope.result = data;
})
.error(function (data, status, headers, config) {
$scope.result = 'エラー';
});
};
}]);
</script>
第1引数が $scope、第2引数が $http なので
この順番で次の配列を controller に渡している
['$scope', '$http', function(~)]
配列アノテーションを使用した場合、関数の引数名は変更しても
正しく動作するが、可読性のために変更せずそのままにしている。