对于日常开发中,难免会有controller之间通信需求。对于controller之间通信有两种方式可以做到。

用 Angular 进行开发,基本上都会遇到 Controller 之间通信的问题,本文对此进行一个总结。

在 Angular 中,Controller 之间通信的方式主要有三种:

1)作用域继承。利用子 Controller 控制父 Controller 上的数据。(父 Controller 中的数据要为引用类型,不能是基本类型,原因参见 AngularJS中的作用域 一文)

2)注入服务。把需要共享的数据注册为一个 service,在需要的 Controller 中注入。

3)基于事件。利用 Angular 的事件机制,使用 $on$emit 和 $boardcast

其中,作用域继承仅限于上下级之间的通信,注入服务和基于事件的机制可以实现任意级别的 Controller 通信。

在 这里 可以查看下面栗子的演示。

作用域继承

原理在 作用域 一文中有讲解,这里直接上栗子。

页面:

<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>

控制器:

angular.module('demo', [])

.controller('parentCtrl', ['$scope', function($scope){
$scope.data = {
name: 'htf'
}
}]) .controller('childCtrl', ['$scope', function($scope){ }])

以上是父 Controller 中的数据是引用类型的情况。如果父 Controller 中的数据是基本类型,可通过$scope.$parent.data 访问。

很显然,这种方式仅适用于父子级间 Controller 的通信。

注入服务

在 Angular 中,服务是一个单例,所以在服务中生成一个对象,该对象就可以利用依赖注入的方式在所有的控制器中共享。

看个栗子,先定义一个 service :

angular.module('demo')
.factory('Data', function(){
return {
name: 'htf'
};
})

页面:

<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>

控制器:

.controller('childCtrl1', ['$scope', 'Data', function($scope, Data){
$scope.data = Data;
}]) .controller('childCtrl2', ['$scope', 'Data', function($scope, Data){
$scope.data = Data;
}])

这种方式适用于任何需要通信的 Controller 之间。

基于事件

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 广播用的事件名不能一样,否则会进入死循环。

看代码:

<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>

关键部分在控制器:

.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 广播和接收事件,那么就可实现同级之间的通信。

看栗子:

<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>

控制器:

.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;
})
}])

参考

  1. 作用域与事件
  2. Angularjs Controller 间通信机制
  3. Communicating Between Controllers In Angular
  4. AngularJS控制器controller如何通信?
  5. controller 间共享数据

angular controller之间通信方式的更多相关文章

  1. angular controller 之间的通信方式

    AngularJS中的controller是个函数,用来向视图的作用域($scope)添加额外的功能,我们用它来给作用域对象设置初始状态,并添加自定义行为. 当我们在创建新的控制器时,angularJ ...

  2. AngularJS进阶(九)控制器controller之间如何通信

    AngularJS控制器controller之间如何通信 注:请点击此处进行充电! angular控制器通信的方式有三种: 1,利用作用域继承的方式.即子控制器继承父控制器中的内容 2,基于事件的方式 ...

  3. AngularJS实战之Controller之间的通信

    我们时常会在不同controller之间进行通信,接下来就介绍三种controller之间的通信方式 一.使用$on.$emit和$broadcast进行controller通信 虽然AngularJ ...

  4. angular view之间的数据传递

    之前写过一篇backbone view之间的传递,由于现在在用angular搞开发,现在也来总结一下.在angular 传递数据通俗的讲叫做 广播 ,在一些文章中,也叫做事件的发布与订阅,在angul ...

  5. angularJS中directive与controller之间的通信

    当我们在angularJS中自定义了directive之后需要和controller进行通讯的时候,是怎么样进行通讯呢? 这里介绍3种angular自定义directive与controller通信的 ...

  6. Angular 1与 Angular 2之间的一些差别

    现在在用ng1.5.8做一个项目,ng的优点和特性我就不用多说了,ng1在陆续更新到1.5/1.6后就没再推出新版本了,ng2已经面世测试很久了,如同很多系统和框架一样,每个大的版本更新都会有新特性加 ...

  7. 通过$broadcast或$emit在子级和父级controller之间进行值传递

    通过$broadcast或$emit在controller之间进行值传递,不过这些controller必须是子级或者父级关系, $emit只能向父级parent controller传递事件event ...

  8. AngularJS 中 Controller 之间的通信

    用 Angular 进行开发,基本上都会遇到 Controller 之间通信的问题,本文对此进行一个总结. 在 Angular 中,Controller 之间通信的方式主要有三种: 1)作用域继承.利 ...

  9. angularjs 中使用 service 在controller 之间 share 对象和数据

    在做angularjs 的UI 时,我们经常会遇到一个页面之间有几个controller,在controller 之间share 公共的一些数据和方法就变得比较困难,目前推荐的做法是创建一个servi ...

随机推荐

  1. NET中级课--文件,流,序列化3

    1.序列化:将对象及状态保存起来. 反序列化就是逆操作. 2.NET提供了一个接口:System.runtime.serialization.IFormatter接口, 还有实现了这个接口的类Bina ...

  2. (转)SQL Server 触发器

    SQL Server 触发器 触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程.触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. Ø 什么是触发器 ...

  3. 如何在程序退出的时候清除activity栈

    在公司里接手了一个后期的项目,由于项目前期对activity栈管理的不够谨慎,所以导致了在某些情况下程序退出的时候没有将activity栈清除掉.在网上找到的无非就是那几种例子,都不是最好的解决办法. ...

  4. 【转载】安装和使用花生壳(linux)

    安装和使用花生壳(linux) 一.安装说明(以CentOS 5为例) 1.安装必要的开发包 [root@localhost ~]# yum install gcc gcc-c++ autoconf ...

  5. 数据库操作CURD

    JDBCCURD操作实例 19. 五 / J2EE / 没有评论   代码目录结构: domain   javabean: util   工具类  jdbcUtil是连接数据mysql数据库的工具类 ...

  6. mysql 使用set names 解决乱码问题的原理

    解决乱码的方法,我们经常使用“set names utf8”,那么为什么加上这句代码就可以解决了呢?下面跟着我一起来深入set names utf8的内部执行原理 先说MySQL的字符集问题.Wind ...

  7. 【转载】solr教程,值得刚接触搜索开发人员一看

    转载:http://blog.csdn.net/awj3584/article/details/16963525 Solr调研总结 开发类型 全文检索相关开发 Solr版本 4.2 文件内容 本文介绍 ...

  8. The FastCGI process exited unexpectedly

    ERROR:HTTP Error 500.0 - Internal Server Error D:\Program Files\php\php-cgi.exe - The FastCGI proces ...

  9. js入门基础7-2 (求模-隔行变色)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. [C++程序设计]有默认参数的函数

    实参与形参的结合是从左至右顺序进行的.因此指定默认值的参数必须放在形参表列中的最右端,否 则出错.例如: void f1(float a,int b=0,int c,char d=′a′); //不正 ...