angular中不同控制器之間的通訊方式
在 Angular 中,Controller 之間通訊的方式主要有三種:
作用域繼承。利用子 Controller 控制父 Controller 上的資料。
注入服務。把需要共享的資料註冊為一個 service,在需要的 Controller 中注入。
基於事件。利用 Angular 的事件機制,使用 $on、$emit 和 $boardcast
一,作用域繼承 (僅適用於父子控制器之間)
html:
<div ng-controller="parentCtrl">
<p>data in parent controller : {{data.name}} </p>
<div ng-controller="childCtrl">
<input type="text" ng-model="data.name">
</div>
</div>
js:
angular.module('demo', [])
.controller('parentCtrl', ['$scope', function($scope){
$scope.data = {
name: 'htf'
}
}])
.controller('childCtrl', ['$scope' , function($scope){
}])
以上是父 Controller 中的資料是引用型別的情況。如果父 Controller 中的資料是基本型別,可通過 $scope.$parent.data 訪問。
二,定義一個 service (這種方式適用於任何需要通訊的 Controller 之間)
js:
angular.module('demo')
.factory('Data', function(){
return {
name: 'htf'
};
})
html:
<div ng-controller ="childCtrl1">
<h3>data in child controller 1 : {{data.name}}</h3>
<input class="form-control" type="text" ng-model="data.name">
</div>
<div ng-controller="childCtrl2">
<h3>data in child controller 2 : {{data.name}}</h3>
<input class="form-control" type="text" ng-model="data.name">
</div>
js:
.controller('childCtrl1', ['$scope', 'Data', function($scope, Data){
$scope.data = Data;
}])
.controller('childCtrl2', ['$scope', 'Data', function($scope, Data){
$scope.data = Data;
}])
三,基於事件
Angular 為$scope 提供了冒泡和隧道機制,$broadcast 會把事件廣播給所有子 Controller,而 $emit 則會將事件冒泡傳遞給父 Controller,$on 則是 Angular 的事件監聽函式,利用這三者,可以實現上下級和同級(需要構造一個共同的父級 Controller)之間的通訊。
上下級之間:
如果是子 Controller 往父 Controller 上傳送事件(從作用域往上傳送事件),使用 scope.$emit
$scope.$emit("someEvent", {});
如果是父 Controller 往子 Controller 上傳送事件(從作用域往下發送事件),使用 scope.$broadcast
$scope.$broadcast("someEvent", {});
無論是 $emit 還是 $broadcast 傳送的事件,都用 $scope.$on 接收:
$scope.$on("someEvent", function(event, data) {
// 這裡取到傳送過來的資料 data
});
同級之間:
同級之間利用事件通訊有兩種方法。一種是利用上下級之間事件傳播的變形,另一種是藉助 $rootScope
藉助父 controller:
在子 Controller 中向父 Controller 觸發一個事件,然後在父 Controller 中監聽事件,再廣播給子 Controller ,這樣通過事件攜帶的引數,實現了資料經過父 Controller,在同級 Controller 之間傳播。
但是要注意,通過父 Controller 作為中介進行傳遞的話,子 Controller 觸發的事件名和父 Controller 廣播用的事件名不能一樣,否則會進入死迴圈。
html:
<div ng-controller="outerCtrl">
<h3>data in outer controller: {{name}}</h3>
<div ng-controller="innerCtrl1">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
<div ng-controller="innerCtrl2">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
</div>
js:
.controller('outerCtrl', ['$scope', function($scope){
$scope.name = 'htf';
$scope.$on('dataChanged', function(event, data){
$scope.name = data;
// 2. 父 Ctrl 監聽到 dataChanged 時間後,觸發 changeData 事件
$scope.$broadcast('changeData', data);
})
}])
.controller('innerCtrl1', ['$scope', function($scope){
$scope.change = function(){
// 1. 子 Ctrl1 中資料改變之後觸發 dataChanged 事件
$scope.$emit('dataChanged', $scope.name);
}
$scope.$on('changeData', function(event, data){
$scope.name = data;
})
}])
.controller('innerCtrl2', ['$scope', function($scope){
$scope.change = function(){
$scope.$emit('dataChanged', $scope.name);
}
// 3. 監聽到 changeData 事件後,改變子 Ctrl2 中 資料
$scope.$on('changeData', function(event, data){
$scope.name = data;
})
}])
藉助 $rootScope
每個 Angular 應用預設有一個根作用域\$rootScope, 根作用域位於最頂層,從它往下掛著各級作用域。
所以,如果子控制器直接使用 $rootScope 廣播和接收事件,那麼就可實現同級之間的通訊。
html:
<div ng-controller="innerCtrlA">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
<div ng-controller="innerCtrlB">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
js:
.controller('innerCtrlA', ['$scope', '$rootScope', function($scope, $rootScope){
$scope.change = function(){
// 廣播事件
$rootScope.$broadcast('nameChanged', $scope.name);
}
$rootScope.$on('nameChanged', function(event, data){
$scope.name = data;
})
}])
.controller('innerCtrlB', ['$scope', '$rootScope', function($scope, $rootScope){
$scope.change = function(){
$rootScope.$broadcast('nameChanged', $scope.name);
}
// 監聽事件
$rootScope.$on('nameChanged', function(event, data){
$scope.name = data;
})
}])