[解決済み] AngularJSでコントローラ間の通信を行う正しい方法は何ですか?
質問
コントローラ間の通信はどのように行うのが正しいのでしょうか?
現在、私は以下のようなひどいごまかしを使っています。
window
:
function StockSubgroupCtrl($scope, $http) {
$scope.subgroups = [];
$scope.handleSubgroupsLoaded = function(data, status) {
$scope.subgroups = data;
}
$scope.fetch = function(prod_grp) {
$http.get('/api/stock/groups/' + prod_grp + '/subgroups/').success($scope.handleSubgroupsLoaded);
}
window.fetchStockSubgroups = $scope.fetch;
}
function StockGroupCtrl($scope, $http) {
...
$scope.select = function(prod_grp) {
$scope.selectedGroup = prod_grp;
window.fetchStockSubgroups(prod_grp);
}
}
解決方法は?
編集
: この回答で取り上げられた問題は、angular.jsで解決されました。
バージョン1.2.7
.
$broadcast
が、未登録スコープでのバブリングを回避し、$emitと同等の速度で実行されるようになりました。
だから、今はできるんです。
-
使用
$broadcast
から$rootScope
-
を使って聴く
$on
ローカルから$scope
イベントについての情報を必要とする
以下、オリジナル回答
を使用しないことを強くお勧めします。
$rootScope.$broadcast
+
$scope.$on
ではなく
$rootScope.$emit
+
$rootScope.$on
. 前者は @numan が指摘したように、深刻なパフォーマンスの問題を引き起こす可能性があります。というのも、このイベントは
すべて
スコープを使用します。
しかし、後者(using
$rootScope.$emit
+
$rootScope.$on
) があります。
ではない
そのため、高速な通信チャネルとして使用することができます。
のアンギュラードキュメントから
$emit
:
イベント名をスコープ階層を通して上方にディスパッチし、登録された
より上位のスコープは存在しないので
$rootScope
バブリングは起こりません。を使っても全く問題ありません。
$rootScope.$emit()
/
$rootScope.$on()
をEventBusとする。
ただし、Controller内から使用する場合は、1つだけ注意点があります。もし、直接
$rootScope.$on()
がコントローラ内にある場合は、ローカルの
$scope
は破棄されます。これは、(サービスとは対照的に)コントローラはアプリケーションのライフタイム中に何度もインスタンス化される可能性があり、その結果バインディングの合計がメモリリークを引き起こすことになるからです :)
登録を解除するには
$scope
's
$destroy
イベントから返された関数を呼び出します。
$rootScope.$on
.
angular
.module('MyApp')
.controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {
var unbind = $rootScope.$on('someComponent.someCrazyEvent', function(){
console.log('foo');
});
$scope.$on('$destroy', unbind);
}
]);
リソースをクリーンアップしなければならないというのは、他のEventBusの実装にも当てはまることなので、angularに限ったことではないのですが、そう言いたいです。
しかし、あなたは
できる
そのような場合のために、自分の生活を楽にする。例えば、モンキーパッチ
$rootScope
を与えて、それを
$onRootScope
で発行されるイベントを購読するものです。
$rootScope
が、ローカルの
$scope
は破棄される。
をモンキーパッチする最もクリーンな方法です。
$rootScope
を提供するために、このような
$onRootScope
メソッドは、デコレータを使うことになります (実行ブロックでもうまくいくでしょうが、内緒です)。
を確認するために
$onRootScope
プロパティを列挙したときに予期せぬものが表示されないようにするためです。
$scope
を使用します。
Object.defineProperty()
を設定し
enumerable
から
false
. ES5 shimが必要になるかもしれないことを念頭に置いてください。
angular
.module('MyApp')
.config(['$provide', function($provide){
$provide.decorator('$rootScope', ['$delegate', function($delegate){
Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
value: function(name, listener){
var unsubscribe = $delegate.$on(name, listener);
this.$on('$destroy', unsubscribe);
return unsubscribe;
},
enumerable: false
});
return $delegate;
}]);
}]);
この方法を用いると、上記のコントローラのコードは次のように簡略化されます。
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
ということで、最終的には
$rootScope.$emit
+
$scope.$onRootScope
.
Btw、私はangularチームにangularコア内でこの問題に対処するよう説得しています。ここで議論が行われています。 https://github.com/angular/angular.js/issues/4574
以下は、perfの影響がどの程度かを示すjsperfです。
$broadcast
を100個だけ使ったまともなシナリオでは
$scope
's.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast
関連
-
[解決済み] let "と "var "の使い分けは?
-
[解決済み] AngularJSを使用して、ブラウザのコンソールで$scope変数にアクセスするにはどうすればよいですか?
-
[解決済み] クラスを条件付きで適用する場合の最適な方法は何ですか?
-
[解決済み] angular-routeとangular-ui-routerの違いは何ですか?
-
[解決済み] AngularJS コントローラにおける 'this' と $scope の比較
-
[解決済み] ng-modelとng-bindの違いは何ですか?
-
[解決済み] AngularJSでコントローラ間の通信を行う正しい方法は何ですか?
-
[解決済み] AngularJS コントローラ間のデータ共有
-
[解決済み】AngularJSのディレクティブスコープにおける「@」と「=」の違いは何ですか?
-
[解決済み】AngularJSのスコーププロトタイピング/プロトタイピング継承のニュアンスとは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン