私はAngularUIルーターにかなり慣れていないので、次のシナリオで使用したいと思います。
レイアウトすべてのページに共通上部のナビゲーションバーには、右側にボタンのあるメニューと、下のスペースを埋めるコンテンツセクションが含まれています。このページには、UIルーターの状態にマップするいくつかのページがあります(ページ1、ページ2、...)。各ページには、独自のメニュー項目と独自のコンテンツを含めることができます。 メニューはスコープをコンテンツと共有する必要があります相互作用するため(たとえば、保存ボタンはコンテンツ内のフォームを送信します。フォームが有効な場合にのみ有効にする必要があります)。
HTMLはおおまかに次のようになります。
<body>
<nav class="...">
<h1>my site</h1>
<div>MENU SHOULD GO HERE</div>
</nav>
<div class="row">
<div class="column ...">
CONTENT SHOULD GO HERE
</div>
</div>
</body>
現在、状態ごとに2つの並列ビューと2つのコントローラーを使用しています。しかし、このように、2つのスコープ/コントローラーは相互作用できません。
では、どのようにそれを達成しますか?
$ scopeはモデルではなく、モデルへの参照であり、データとビューの間に接着します。 2つ以上の$ scopesで、コントローラーが1つのモデル/状態/データを共有する必要がある場合は、angularサービスを登録することにより、シングルトンオブジェクトインスタンスを使用します。あなたが好きなようにコントローラー、そしてそれからすべてはその1つの真実の源からうまくいくことができます。
これは、navbarとbodyの$ scopesをui-routerにリンクする1つのファクトリのデモです http://plnkr.co/edit/P2UudS?p=preview (左側のタブのみ)
ui-router(viewCはnavbarです):
$stateProvider
.state('left', {
url: "/",
views: {
"viewA": {
controller: 'LeftTabACtrl',
template: 'Left Tab, index.viewA <br>' +
'<input type="checkbox" ng-model="selected2.data" />' +
'<pre>selected2.data: {{selected2.data}}</pre>'
},
{...},
"viewC": {
controller: 'NavbarCtrl',
template: '<span>Left Tab, index.viewC <div ui-view="viewC.list"></div>' +
'<input type="checkbox" ng-model="selected.data" />' +
'<pre>selected.data: {{selected.data}}</pre></span>'
}
}
})
工場とコントローラー:
app.factory('uiFieldState', function () {
return {uiObject: {data: null}}
});
app.controller('NavbarCtrl', ['$scope', 'uiFieldState', '$stateParams', '$state',
function($scope, uiFieldState, $stateParams, $state) {
$scope.selected = uiFieldState.uiObject;
}
]);
app.controller('LeftTabACtrl', ['$scope', 'uiFieldState', '$stateParams', '$state',
function($scope, uiFieldState, $stateParams, $state) {
$scope.selected2 = uiFieldState.uiObject;
}
]);
ご覧のとおり、ファクトリオブジェクト{uiObject: {data: null}}
はuiFieldState
でコントローラーに注入され、次にその単純な$scope.selected = uiFieldState.uiObject;
ファクトリをスコープに接続するためのng-model="selected.data"
.`
次を使用する必要があります。
$on and $emit
データを送信するエミットコントローラー。
angular.module('MyApp').controller('MyController', ['$scope', '$rootScope', function ($scope, $rootScope){
$rootScope.$emit('SomeEvent', data);
}]);
$ rootScopeを安全な方法で実装して、使用後にものを破棄して修正する方法の例:
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);
},
enumerable: false
});
return $delegate;
}]);
}]);
そして、処理する必要のあるデータを持つコントローラー。
angular.module('MyApp')
.controller('MySecondController', ['$scope', function MyController($scope) {
$scope.$onRootScope('SomeEvent', function(event, data){
console.log(data);
});
}
]);
構成で定義した$ scopesメソッド$ onRootScopeを使用する代わりに、$ rootScopeを渡すことができます。ただし、これは$ emitおよび$ onRootScopeを使用するための推奨される方法ではありません。
$ emitを使用する代わりに、いつでも$ broadcastを使用できます。ただし、これにより、アプリの成長に伴って非常に大きなパフォーマンスの問題が発生します。すべてのコントローラーを介してデータをバブルするため。
コントローラが相互に親と子である場合、コントローラは$ rootScopeを使用する必要はありません。
$ emitと$ broadcastの違いの例を次に示します。 jsFiddle
そして、それらは本当にパフォーマンスの違いです。