『AngularJS: Up and Running』読書メモ 第2章 コントローラーとディレクティブ

AngularJS: Up and Running

AngularJSのモジュール

最初に学ぶべき概念は「モジュール」である。
AngularJSでは、モジュールによって、関連するコードを1つにパッケージする。
AngularJSのモジュールには2つの部品がある。

  • モジュールは自身のコントローラー、サービス、ファクトリ、ディレクティブを定義することができる
    • これらにはモジュールを通してアクセスできる
  • モジュールは別のモジュールに依存することができる
    • モジュールの初期化処理において依存モジュールを指定する

モジュールは、関連するJavaScriptの容れ物であるのと同時に、AngularJSがアプリケーションを開始するのに使用するものでもある。
ng-appディレクティブで、アプリケーションのエントリポイントを指定できる。

angular.moduleメソッドの第1引数はモジュール名、第2引数は依存しているモジュール名の配列になる。
第2引数を渡さない場合、myAppという名前のモジュールを探して返す。

コントローラーの作成

AngularJSにおけるコントローラーの役割は以下のようになる。

  • サーバから現在のUIに合わせたデータを取得する
  • ユーザにどのデータを見せるか決める
  • 表示のロジック
  • ユーザーとのやりとり

UIに関係のないコントローラーは存在しない(UIに関係ないビジネスロジックはサービスに書くべき)。
コントローラーは以下のように定義する。

AngularJSのモジュールのcontrollerメソッドを使って、コントローラーを定義することができる。
controllerメソッドは第1引数にコントローラー名、第2引数に配列を取る。
第2引数の配列には、依存しているモジュール名の文字列を入れ、配列の最後の要素にコントローラーとなる関数を入れる。
(依存モジュールが無い場合は関数だけを入れる)

なお、第2引数には配列でなく関数を渡すこともできるが、JavaScriptコードを圧縮すると動作しなくなるため非推奨。

また、従来のサンプルコードでよく使われていた、グローバルに関数を定義してコントローラーとする方法は、1.3以降では動かない。

ng-controllerディレクティブを使うことで、コントローラーを指定できる。

ControllerAs記法はAngularJS1.2で導入された機能で、コントローラー自身のプロパティにビューからアクセスできるようにすることができる。
上記サンプルでは、ng-controllerのControllerAs記法でMainCtrlに別名をつけ、MainCtrlに定義されたプロパティにアクセスしている。

コントローラーがネストされた複雑なUIでは、ビューの変数がどこから来ているか判別するのが難しいことがある。
ControllerAs記法を使うと、コントローラーの名前によって変数の出処がはっきりする。

配列を扱う

ng-repeatディレクティブを使うことで、配列を表示することができる。

ng-repeatディレクティブを使って、MainCtrl.notesを表示するコードは以下。

ここで、ng-repeatの付いた要素と、その中身の要素は、繰り返しの際のテンプレートになる。
上記コードの場合、中にspanを含むdivが3つ生成される。

ここでは、ビューで{{}}の代わりにng-bindディレクティブを使っている。
{{}}を使うと、AngularJSアプリケーションの読み込みが完了するまで{{}}が表示されてしまうことがあるが、ng-bindではこの問題を回避できる。
この問題は、ng-cloakディレクティブを使うことでも回避可能である。

AngularJSのロードが完了するのを待つ

angular.js(又はangular.min.js)を読み込むと、以下のCSSが自動的に定義される。

[ng-cloak]は、ng-cloakという属性を持つ要素に対するセレクタなので、このCSSルールでは、ng-cloak属性のついた要素を非表示にする。
ロードが完了すると、AngularJSはng-cloak属性を要素から取り除くため、要素が画面上に表示される。
bodyタグにng-cloakをつけることもできるが、細かなパーツごとにつけていった方がユーザビリティが良い。

angular.jsのソースコードの読み込みが完了するまで、上記CSSは定義されていないことに注意が必要。
※一般に、CSSは先に、JavaScriptは後に読み込むほうがページ表示のパフォーマンスが良くなる。
上記CSSルールを自前のCSSファイルの中で定義しておくことで、より確実に非表示にすることができる。

AngularJSの処理の流れ

  1. HTMLの読み込みが完了し、JavaScriptの読み込みが始まる
  2. ドキュメント全体の読み込みが完了し、AngularJSの動作が始まる
  3. ng-appディレクティブを見つけると、関連するモジュールを探して読み込む
  4. ng-app配下のDOMを探索し、ディレクティブやバインド文を探す
  5. ng-controller又はng-repeatディレクティブを見つけたら、その都度scopeを作成する
  6. HTMLからアクセスされる変数にウォッチャーとリスナーを登録する(2way-binding)
  7. AngularJSはモデルのデータが変わった場合にのみ、UIの更新を行う

ワンタイムバインディングによるngBindの最適化

AngularJS1.3以上では、ワンタイムバインディングを利用することでngBindのパフォーマンスを最適化できる。

以下のようなデータがあると想定する。

通常のngBindと、ワンタイムバインドを使った構文の例は以下。

ワンタイムバインディングの方では、変数の前に「::」をつけている。
この記号をつけると、変数は初回表示の時にだけ使用され、その後更新はされなくなる。
ページ内で双方向バインディングされている変数の数が多くなるほど、更新処理のオーバーヘッドは大きくなる。
ワンタイムバインディングを使うことで、更新処理のオーバーヘッドを最小化することができる。

その他のディレクティブ

ng-show/ng-hide

ng-show/ng-hideディレクティブを使うと、要素の表示非表示を制御することができる。

ng-show/hideの条件には式を渡すこともできる。

ng-show/hideで真として評価される値は、Booleanのtrue、空白でない文字列、0でない数値、nullでないJavaScriptのオブジェクトである。

ng-class

ng-classディレクティブはCSSクラスを付け外しするのに使用される。
ng-classディレクティブには、適用するクラスを文字列として渡す使い方と、オブジェクトを渡す使い方がある。

オブジェクトを渡す方法の場合、渡すオブジェクトの値がtrueである要素のキーがクラスとして適用される。
実際のコードでは以下のような実装になる。

以下はビュー。itemという変数にstatusというプロパティがあるとする。

上記コードの場合、item.statusがtrueであれば.doneが、falseであれば.pendingが適用される。

ng-repeatを扱う

ng-repeatは繰り返し行うディレクティブである。

オブジェクトをng-repeatする

以下のようなオブジェクトがあるとする。

このオブジェクトをng-repeatで回す場合は、ビューを以下のように書く。

ng-repeatはオブジェクトをループする場合、アルファベット順で、大文字の方が先になる。そのため、上の例ではMisko, brad, shyamの順に表示される。

ng-repeatは、value in Array又は(key, value) in Objectという形をとる。配列の場合には、ng-repeatは配列の先頭から順に表示する。

ng-repeatのヘルパー変数

ng-repeatには、HTMLテンプレートで利用できるヘルパー変数が存在する。

Track by ID

デフォルトでは、ng-repeatは繰り返しの度に新しいDOM要素を作る。
しかし、パフォーマンス最適化のため、作成されるオブジェクトが同じであればDOMのキャッシュ又は再利用を行う。
(同一性の検証にはオブジェクトのハッシュ値を用いている)

オブジェクトの同一性に関係なく、同じDOM要素を再利用して欲しいこともある。
この場合には、AngularJSにトラッキングのための情報を渡すことができる。

track by にトラッキングのための変数を設定すると、この変数の値が同じであればDOM要素が再利用される。

$$ で始まる変数を使ってはいけない

$$ で始まる変数を、アプリケーションのコードで使ってはいけない。
AngularJSは $$ で始まる変数をAngularJS内のプライベート変数を示すものとして使用しており、これらの変数が将来に渡っても使える保証はない。

複数のHTML要素にまたがったng-repeat

テーブルを2行ごと(

2つごと)に繰り返す、といった操作が必要になることがある。
ng-repeat-startとng-repeat-endディレクティブを使うことで、AngularJSに、ng-repeatの開始点と終了点を知らせることができる。

コメントを残す