ng.$rootScope.Scope
- 概要
- 使用方法
- $apply(exp)
- $broadcast(name, args)
- $destroy()
- $digest()
- $emit(name, args)
- $eval(expression, locals)
- $evalAsync(expression)
- $new(isolate)
- $on(name, listener)
- $watch(watchExpression, listener, objectEquality)
- $watchCollection(obj, listener)
- $id
- $destroy
概要
rootのスコープは、$rootScopeキーを使用して$injectorから取得することが出来ます。 子スコープは、$new()メソッドを使用して作られます。 (ほとんどのスコープは、HTMLテンプレートのコンパイル実行時に自動的に作成されます。)
下記は、スコープと対話する方法を示す、シンプルなスコープのスニペットです。
var scope = $rootScope.$new();
scope.salutation = 'Hello';
scope.name = 'World';
expect(scope.greeting).toEqual(undefined);
scope.$watch('name', function() {
scope.greeting = scope.salutation + ' ' + scope.name + '!';
}); // watchの初期化
expect(scope.greeting).toEqual(undefined);
scope.name = 'Misko';
// watchがまだ呼び出されていないため、値がまだ古い
expect(scope.greeting).toEqual(undefined);
scope.$digest(); // 全てのwatchを発火
expect(scope.greeting).toEqual('Hello Misko!');
継承
下記の例のように、スコープは親スコープから継承することが出来ます。
var parent = $rootScope;
var child = parent.$new();
parent.salutation = "Hello";
child.name = "World";
expect(child.salutation).toEqual('Hello');
child.salutation = "Welcome";
expect(child.salutation).toEqual('Welcome');
expect(parent.salutation).toEqual('Hello');
使用方法
Scope([providers][, instanceCache]);
引数 | 説明 |
---|---|
providers(optional) |
型: 現在のスコープのために提供される必要がある、サービスファクトリーのマップを指定します。 |
instanceCache(optional) |
型: プロバイダが提供するサービスを追加/上書きすべき、予めインスタンス化されたサービスを提供します。 これを使用すればユニットテストとデフォルトサービスをの上書きが必要な際に、手軽に行うことが出来ます。 |
戻り値 | 説明 |
型: 新しく作成されたスコープを返します。 |
$apply(exp)
$apply()は、Angularフレームワークの外側からAngular内のものとして式を実行するのに使用されます。 (例えば、ブラウザのDOMイベント、setTimeout、XHR、またはサードパーティ製のライブラリ) 例外処理、監視実行のライフサイクルのある適したスコープで実行される必要があるため、Angularのフレームワーク内で呼び出します。
$apply()の擬似コード
function $apply(expr) {
try {
return $eval(expr);
} catch (e) {
$exceptionHandler(e);
} finally {
$root.$digest();
}
}
スコープの$apply()メソッドは、下記のような段階を通して推移します。
- $eval()メソッドを使用して式を実行します。
- 式の実行による何らかの例外は、$exceptionHandlerサービスに渡します。
- watchリスナーは、$digest()メソッドを使用した式の実行後、即座に発火されます。
引数 | 説明 |
---|---|
exp(optional) |
型: 実行するAngular式を指定します。
|
戻り値 | 説明 |
型: 式の実行結果が返されます。 |
$broadcast(name, args)
ng.$rootScope.Scope#$onに登録されたリスナーに指定した名前のイベント名の通知を発行します。 これは子スコープ(更にその子スコープ)へ、伝搬していきます。
イベントのライフサイクルは、$broadcastが呼び出されたスコープで開始されます。 このスコープ上で、nameのイベントをリッスンする全てのリスナーは、通知を取得します。 その後、イベントは現在のスコープ全てに直接または間接的に伝搬し、この方法に沿って登録されているリスナーを呼び出します。 このイベントは、キャンセルすることが出来ません。
$destroy()
親スコープから、現在のスコープ(と、この子スコープ全て)を削除します。 この除去によって、$digest()の呼び出しが現在のスコープとその子スコープへの伝搬が無くなることを意味します。 また、現在のスコープがガベージコレクションの対象となることも意味します。
$destroy()は、ループ処理の展開を管理するngRepeatのようなディレクティブで使用される事が多いです。
スコープが削除される直前、$destroyイベントがこのスコープ上でブロードキャスト(broadcast)されます。 そのためアプリケーションのコードに、必要なクリーンアップを行う処理を、$destroyイベントハンドラに登録することが可能です。
AngularJSでは、DOMから要素が削除される前に、 DOMの紐付けをクリーンアップするのに使用されるjQuerbyイベントの$destoryがあることにも注意してください。(翻訳に自信なし)
$digest()
現在のスコープとその子スコープの全てに対する監視処理です。 監視のリスナーはモデルを変更することが出来るため、以降のリスナーの発火まで、 $digest()は監視の呼び出しを保持します。(翻訳に自信なし) これは、無限ループになる可能性があることを意味します。 この関数は、反復回数が10を超えた場合、'Maximum iteration limit exceeded.'をスローします。
通常、コントローラー、またはディレクティブ内で直接$digest()を呼び出すことはありません。 代わりに、$digestの実行を矯正する$apply()を呼び出すべきです。(通常、ディレクティブ内から行われる)
もし、$digest()が呼び出される度に通知が行われて欲しい場合、 リスナー無しで$watch()にwatchExpression(監視式?)関数を登録することが出来ます。
ユニットテストでは、スコープのライフサクルでシミュレートするために、 $digest()を呼び出す必要があるかもしれません。
var scope = ...;
scope.name = 'misko';
scope.counter = 0;
expect(scope.counter).toEqual(0);
scope.$watch('name', function(newValue, oldValue) {
scope.counter = scope.counter + 1;
});
expect(scope.counter).toEqual(0);
scope.$digest();
// no variable change
expect(scope.counter).toEqual(0);
scope.name = 'adam';
scope.$digest();
expect(scope.counter).toEqual(1);
$emit(name, args)
ng.$rootScope.Scope#$onに登録されているリスナーに、指定された名前のイベント通知を スコープの階層を通して上方に送ります。
イベントのライフサイクルは、$emitが呼び出されたスコープから開始されます。 このスコープ上で、nameのイベントをリッスンしている全てのリスナーは、通知を取得します。 その後、イベントはrootスコープに向かって上方に進み、 その途中の登録されているリスナーを呼び出します。 もし、その中のリスナーの1つがキャンセルすると、イベントの伝播は停止されます。
リスナーから発行された何らかの例外は、$exceptionHandlerサービスに渡されます。
引数 | 説明 |
---|---|
name |
型: 発行するイベント名を指定します。 |
args |
型: イベントのリスナーに渡す任意の引数のセットを指定します。 |
戻り値 | 説明 |
型: イベントオブジェクトが返ります。 (ng.$rootScope.Scope#$on参照) |
$eval(expression, locals)
現在のスコープ上で指定された式(expression)を実行し、結果を返します。 何らかの例外が式内で発生した場合、それは伝搬されます(catchしません)。 これは、Angular式を評価する際に便利です。
var scope = ng.$rootScope.Scope();
scope.a = 1;
scope.b = 2;
expect(scope.$eval('a+b')).toEqual(3);
expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
引数 | 説明 |
---|---|
expression(optional) |
型: 実行されるAngular式を指定します。
|
locals(optional) |
型: スコープ内の値を上書きするのに便利な、ローカル変数オブジェクトを指定します。 |
戻り値 | 説明 |
型: 式で評価された結果が返ります。 |
$evalAsync(expression)
現在のスコープ上で、式(expression)を遅延して実行します。
$evalAsyncは式が実行される際に、下記のことを保証するものではありません。(翻訳に自信なし)
- 評価するようにスケジュールされている関数の後に実行されるということ。(出来れば、DOM描画の前に)
- 式が評価後に少なくとも1つの$digestサイクルが実行されるということ。
式の実行による何らかの例外は、$exceptionHandlerサービスに渡されます。
注意: もし、この関数が$digestサイクルの外側で呼ばれた場合、新しい$digestサイクルがスケジュールされます。 ただし、こういった場合は、常に$applyの呼び出し内から、モデルを変更するコードを呼び出すことが推奨されています。 これには、$evalAsync経由で評価されるコードが含まれています。
引数 | 説明 |
---|---|
expression(optional) |
型: 実行するAngular式を指定します。
|
$new(isolate)
新しい子スコープを作成します。
親スコープは、$digest()と$digest()イベントに伝搬します。 このスコープは、$destroy()を使用して階層スコープから削除することが可能です。
$destroy()は、スコープとその子スコープを恒久的に親スコープから取り除きたい際に、スコープ上で呼び出さなければいけません。 そうすることで、モデル変更の探知とリスナーの通知に関することを停止することが出来ます。
引数 | 説明 |
---|---|
isolate |
型: trueにすると、親スコープからプロトタイプ継承を行いません。 スコープは孤立するため、親スコープのプロパティを参照することは出来ません。 ウィジットを作成する際に、誤って親の状態を読み込むの防ぐのに便利です。 |
戻り値 | 説明 |
型: 新しく作成された子スコープが返ります。 |
$on(name, listener)
与えられた型のイベントをリッスンします。 イベントのライフサイクルについては、$emitを参照してください。
イベントリスナー関数のフォーマットは、function(event, args...)
です。
リスナーに渡されるイベントのオブジェクトは、下記の属性を持ちます。
引数 | 説明 |
---|---|
name |
型: リッスンするイベント名を指定します。 |
listener |
型: イベントが発行された際に呼び出す関数を指定します。 |
戻り値 | 説明 |
型: このリスナーの登録を抹消する関数を返します。 |
$watch(watchExpression, listener, objectEquality)
監視式(watchExpression)が変更される度に、実行されるリスナーコールバックを登録します。
-
watchExpression
は、$digest()が呼び出される度に呼び出され、監視される値を返すべきです。 ($digest()は、watchExpression
の変更を検知する際に再実行するため、 $digest()毎に複数実行することが可能で、冪等(Wikipedia)であるべきです。) (翻訳に自信なし) - リスナーは、現在のwatchExpressionとその前のwatchExpressionが等しくない場合にのみ、呼び出されます。 (初期化実行については、下記を参照してください) 等しい・等しくないの判定は、angular.equals関数に沿って決定されます。 後の比較のためにオブエジェクトの値を保存するために、angular.copy関数が使用されます。 これはまた、複雑なオプションの監視は、メモリーとパフォーマンスにマイナスの影響を持つことも意味します。
- 監視リスナーはモデルを変更する可能性があり、それが別のリスナーの発火要因になるかもしれません。 これは、変更が検出されなくなるまで監視を再実行するために起こりえます。 再実行の繰り返し限度を10回にすることで、無限ループのデッドロックを防ぎます。
もし、$digestが呼び出される度に通知が欲しい場合は、
リスナー無しのwatchExpression
関数を登録することが出来ます。
(watchExpression
は、変更が検知される際に、$digestサイクル毎に複数回実行することが出来るため、
リスナーのための複数回の呼び出しに対する対応が準備されます。(翻訳に自信なし))
スコープに監視が登録された後に、監視を初期化するためにリスナー関数が非同期で($evalAsyncを介して)呼び出されます。 watchExpressionの結果が変更されない場合、リスナーが呼び出されてしまうために、稀に望ましくないという事があります。(翻訳に自信なし) リスナー関数内でこうようなケースでも検知するために、newVal(新しい値)とoldVal(古い値)を比較することが可能です。 もし、これらの2つの値が全く同じ(===)であれば、リスナーは初期化のために呼び出されます。(翻訳に自信なし)
下記は、$watchリスナーとして関数を使用する説明を含む例になります。
// スコープは$rootScopeとして依存注入されたものとします。
var scope = $rootScope;
scope.name = 'misko';
scope.counter = 0;
expect(scope.counter).toEqual(0);
scope.$watch('name', function(newValue, oldValue) {
scope.counter = scope.counter + 1;
});
expect(scope.counter).toEqual(0);
scope.$digest();
// 値の変更無し
expect(scope.counter).toEqual(0);
scope.name = 'adam';
scope.$digest();
expect(scope.counter).toEqual(1);
// リスナー関数を使用
var food;
scope.foodCounter = 0;
expect(scope.foodCounter).toEqual(0);
scope.$watch(
// これは、リスナー関数です。
function() { return food; },
// これは、変更ハンドラです。
function(newValue, oldValue) {
if ( newValue !== oldValue ) {
// 値が変更された場合のみ、カウンターを加算
scope.foodCounter = scope.foodCounter + 1;
}
}
);
// digestが実行されていないため、カウンターはゼロ
expect(scope.foodCounter).toEqual(0);
// digestを実行しますが、foodは変更されていなため、
// カウンターはゼロのままです。
scope.$digest();
expect(scope.foodCounter).toEqual(0);
// foodを更新し、digestを実行。
// カウンターが加算されていることが確認できます。
food = 'cheeseburger';
scope.$digest();
expect(scope.foodCounter).toEqual(1);
引数 | 説明 |
---|---|
watchExpression |
型: $digestサイクル毎に評価される式を指定します。 戻り値が変更されていた場合、リスナーの呼び出しがトリガされます。
|
listener(optional) |
型: watchExpressionが変更された値を返す度に呼び出されるコールバックです。
|
objectEquality(optional) |
型: オブジェクトの参照ではなく、等しいかどうかを比較します。 |
戻り値 | 引数 |
型: リスナーの登録を抹消する関数を返します。 |
$watchCollection(obj, listener)
オブジェクトのプロパティを監視し、何らかのプロパティの変更があれば発火します。 (配列であれば配列の項目の監視が含まれ、オブジェクトのマップであればプロパティの監視が含まれます) もし変更が検知されると、リスナーのコールバックが発火されます。
$scope.names = ['igor', 'matias', 'misko', 'james'];
$scope.dataCount = 4;
$scope.$watchCollection('names', function(newNames, oldNames) {
$scope.dataCount = newNames.length;
});
expect($scope.dataCount).toEqual(4);
$scope.$digest();
//まだ4であり、変更はされていない
expect($scope.dataCount).toEqual(4);
$scope.names.pop();
$scope.$digest();
// 変更が行われました
expect($scope.dataCount).toEqual(3);
引数 | 説明 |
---|---|
obj |
型: 式として評価されます。 式の値は、各$digestのサイクルで監視される際に、オブジェクトまたは配列として評価されるべきです。 これに含まれる何らかの変更が行われると、リスナーの呼び出しがトリガされます。 |
listener |
型:
|
戻り値 | 説明 |
型: このリスナーの登録を抹消する関数を返します。 この関数が実行されると、この内部watchオペレーションが取り除かれます。 |
$id
戻り値 | 説明 |
---|---|
型: デバッグで便利な、一意のスコープID(単純な英数字のシーケンス番号)を返します。 |
$destroy
スコープとその子スコープがdestroy(削除)された際に、ブロードキャストされます。
AngularJSには、DOMから要素が削除される前に、DOMの紐付けをクリーンアップされるのに使用される、 $destroyのjQueryイベントも存在することに注意してください。
型: broadcast
対象: 削除されるスコープ
© 2017 Google
Licensed under the Creative Commons Attribution License 3.0.
このページは、ページトップのリンク先のAngularJS公式ドキュメント内のページを翻訳した内容を基に構成されています。 下記の項目を確認し、必要に応じて公式のドキュメントをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。
- AngularJSの更新頻度が高いため、元のコンテンツと比べてドキュメントの情報が古くなっている可能性があります。
- "訳注:"などの断わりを入れた上で、日本人向けの情報やより分かり易くするための追記を行っている事があります。