AngularJS
角度$スコープ
サーチ…
備考
Angularはスコープのツリーを使用して、コントローラ、ディレクティブなどのロジックをビューにバインドし、AngularJSの変更検出の主なメカニズムです。スコープの詳細については、 docs.angularjs.orgを参照してください。
ツリーのルートは、注入可能なサービス$ rootScope経由でアクセス可能です 。すべての子$スコープは、親$スコープのメソッドとプロパティを継承し、子が角度サービスを使用せずにメソッドにアクセスできるようにします。
$ scope継承の基本的な例
angular.module('app', [])
.controller('myController', ['$scope', function($scope){
$scope.person = { name: 'John Doe' };
}]);
<div ng-app="app" ng-conroller="myController">
<input ng-model="person.name" />
<div ng-repeat="number in [0,1,2,3]">
{{person.name}} {{number}}
</div>
</div>
この例では、ng-repeatディレクティブは、新しく作成された各子に対して新しいスコープを作成します。
これらの作成されたスコープは、親スコープの子(この場合はmyControllerによって作成されたスコープ)です。したがって、それらはpersonなどのすべての割合を継承します。
プリミティブ値の継承を避ける
JavaScriptでは、非割り当てプリミティブ (オブジェクト、配列、機能、などの値多くのより)は、割り当てられた値を参照する(メモリ内のアドレス)を維持します。
2つの異なる変数にプリミティブ値(文字列、数値、ブール値、またはシンボル)を割り当て、その変数を変更しても、両方が変更されることはありません。
var x = 5;
var y = x;
y = 6;
console.log(y === x, x, y); //false, 5, 6
しかし、非プリミティブな値では、両方の変数が同じオブジェクトへの参照を保持しているだけなので、一方の変数を変更するともう一方の変数が変更されます:
var x = { name : 'John Doe' };
var y = x;
y.name = 'Jhon';
console.log(x.name === y.name, x.name, y.name); //true, John, John
angleでは、スコープが作成されると、そのスコープは親のすべてのプロパティに割り当てられますが、その後のプロパティの変更は、親スコープが非プリミティブの値である場合にのみ親スコープに影響します。
angular.module('app', [])
.controller('myController', ['$scope', function($scope){
$scope.person = { name: 'John Doe' }; //non-primitive
$scope.name = 'Jhon Doe'; //primitive
}])
.controller('myController1', ['$scope', function($scope){}]);
<div ng-app="app" ng-controller="myController">
binding to input works: {{person.name}}<br/>
binding to input does not work: {{name}}<br/>
<div ng-controller="myController1">
<input ng-model="person.name" />
<input ng-model="name" />
</div>
</div>
注意:Angularスコープでは、組み込みディレクティブやカスタムディレクティブ、 $scope.$new()
関数など、さまざまな方法で作成でき、スコープツリーを把握することは不可能です。
スコープのプロパティとして非プリミティブな値のみを使用すると、継承しないプロパティやスコープの継承を認識している他のケースが必要な場合を除き、安全な場所に置かれます。
アプリ全体で利用可能な関数
このアプローチは、スコープツリー内に関数が配置されている場所とスコープ継承を意識することをプログラマが覚えておく必要があるため、角型アプリケーションの設計としては悪いと考えられます。多くの場合、サービスを注入することが望ましいでしょう( 角度練習 - スコープの継承と注入を使用します) 。
この例では、アプリケーション全体を設計するベストプラクティスではなく、スコープ継承をどのように使用してニーズを把握できるかを示しています。
場合によっては、スコープの継承を利用して関数をrootScopeのプロパティとして設定することもできます。このように、アプリ内のすべてのスコープ(分離されたスコープを除く)はこの関数を継承し、アプリ内のどこからでも呼び出すことができます。
angular.module('app', [])
.run(['$rootScope', function($rootScope){
var messages = []
$rootScope.addMessage = function(msg){
messages.push(msg);
}
}]);
<div ng-app="app">
<a ng-click="addMessage('hello world!')">it could be accsessed from here</a>
<div ng-include="inner.html"></div>
</div>
inner.html:
<div>
<button ng-click="addMessage('page')">and from here to!</button>
</div>
カスタム$ scopeイベントの作成
通常のHTML要素と同様に、$スコープは独自のイベントを持つことができます。 $ scopeイベントは、以下の方法で購読することができます:
$scope.$on('my-event', function(event, args) {
console.log(args); // { custom: 'data' }
});
イベントリスナーの登録を解除する必要がある場合、 $ on関数はバインド解除関数を返します。上記の例を続行するには:
var unregisterMyEvent = $scope.$on('my-event', function(event, args) {
console.log(args); // { custom: 'data' }
unregisterMyEvent();
});
独自の$スコープイベント$ broadcastと$ emitをトリガするには、2つの方法があります。特定のイベントのスコープを親に通知するには、 $ emitを使用します
$scope.$emit('my-event', { custom: 'data' });
上記の例では、親スコープのmy-event
イベントリスナーをトリガーし、イベントのstopPropagation
をリスナーが呼び出さない限り、スコープツリーを$ rootScopeまで続けます。 $ emitでトリガされたイベントだけがstopPropagation
ことがstopPropagation
$ emitの逆は$ broadcastです 。スコープの子であるスコープツリー内のすべての子スコープで、 $ broadcastを呼び出したイベントリスナーをトリガーします。
$scope.$broadcast('my-event', { custom: 'data' });
$ブロードキャストでトリガーされたイベントはキャンセルできません。
$ scope関数を使う
$ rootscopeの関数宣言には利点がありますが、$ scopeサービスによって注入されるコードのどの部分も$ scope関数を宣言することもできます。たとえば、コントローラー。
コントローラ
myApp.controller('myController', ['$scope', function($scope){
$scope.myFunction = function () {
alert("You are in myFunction!");
};
}]);
これでコントローラから関数を呼び出すことができます:
$scope.myfunction();
または、その特定のコントローラの下にあるHTMLを介して:
<div ng-controller="myController">
<button ng-click="myFunction()"> Click me! </button>
</div>
指令
角度指示はスコープを使用できる別の場所です:
myApp.directive('triggerFunction', function() {
return {
scope: {
triggerFunction: '&'
},
link: function(scope, element) {
element.bind('mouseover', function() {
scope.triggerFunction();
});
}
};
});
あなたのHTMLコードに同じコントローラの下で:
<div ng-controller="myController">
<button trigger-function="myFunction()"> Hover over me! </button>
</div>
もちろん、同じことについてngMouseoverを使用することもできますが、ディレクティブの特別な点は、好みの方法でカスタマイズできることです。そして、あなたは$ scope関数をそれらの中で使う方法を知っています。
どのようにディレクティブの範囲を制限することができますか、なぜこれを行うでしょうか?
スコープは、親コントローラ、ディレクティブ、およびディレクティブテンプレート間の通信に使用する「グルー」として使用されます。 AngularJSアプリケーションがブートストラップされるたびに、rootScopeオブジェクトが作成されます。コントローラ、ディレクティブ、およびサービスによって作成される各スコープは、rootScopeからプロトタイプ的に継承されます。
はい、指示の範囲を制限できます。ディレクティブのために独立したスコープを作成することで、これを行うことができます。
ディレクティブスコープには3種類あります。
- スコープ:False(ディレクティブは親スコープを使用します)
- スコープ:True(ディレクティブは新しいスコープを取得します)
- スコープ:{}(ディレクティブは新しい独立スコープを取得します)
新しい分離スコープのディレクティブ:新しい分離スコープを作成すると、親スコープから継承されません。この新しいスコープは、親スコープから完全に切り離されているため、Isolatedスコープと呼ばれます。どうして?分離されたスコープを使用する必要があります。カスタムディレクティブを作成する場合は、ディレクティブが汎用であり、アプリケーション内のどこにでも配置されるようにするため、分離スコープを使用する必要があります。親スコープは、ディレクティブスコープに干渉することはありません。
隔離されたスコープの例:
var app = angular.module("test",[]);
app.controller("Ctrl1",function($scope){
$scope.name = "Prateek";
$scope.reverseName = function(){
$scope.name = $scope.name.split('').reverse().join('');
};
});
app.directive("myDirective", function(){
return {
restrict: "EA",
scope: {},
template: "<div>Your name is : {{name}}</div>"+
"Change your name : <input type='text' ng-model='name'/>"
};
});
AngularJSは分離スコープ用に3種類のプレフィックスを用意しています:
- "@"(テキストバインディング/一方向バインディング)
- "="(直接モデル結合/双方向結合)
- "&"(ビヘイビアバインディング/メソッドバインディング)
これらの接頭辞はすべて、次のように指令要素の属性からデータを受け取ります。
<div my-directive
class="directive"
name="{{name}}"
reverse="reverseName()"
color="color" >
</div>