在同个angular应用的控制器之间进行通信可以有很多种不同的方式,本文主要讲两种:

基于scope继承的方式和基于event传播的方式

基于scope继承的方式

最简单的让控制器之间进行通信的方法是通过scope的继承。假设有两个控制器Parent、Child,Child 在 Parent 内,那Child 可以称为子控制器,它将继承父控制器Parent的scope。这样,Child就可以访问到Parent的scope中的所有函数和变量了。
需要注意的是,由于scope的继承也是基于Js的原型继承,如果变量是基本类型的,那在Child中的修改(写),有可能会导致Parent中的数据变脏。

基本类型变量的继承

  1. function Sandcrawler($scope) {
  2. $scope.location = 'Mos Eisley North';
  3. $scope.move = function(newLocation) {
  4. $scope.location = newLocation;
  5. }
  6. }
  7. function Droid($scope) {
  8. $scope.sell = function(newLocation) {
  9. $scope.location = newLocation;
  10. }
  11. }
  12. // html
  13. <div ng-controller="Sandcrawler">
  14. <p>Location: </p>
  15. <button ng-click="move('Mos Eisley South')">Move</button>
  16. <div ng-controller="Droid">
  17. <p>Location: </p>
  18. <button ng-click="sell('Owen Farm')">Sell</button>
  19. </div>
  20. </div>

看完上面的代码我们知道,location 属性是直接被注册到 $scope 中的,Droid控制器所拥有的scope从Sandcrawler控制器的scope中继承了这个属性并且可以读取它。看以下两个假设场景:

  • 如果 Sandcrawler 中改变了 location 属性,在 Droid 中也会读取到这个改变;在 view 中的表现则是:点击了Move 按钮的话,两个 p 标签都会显示 Mos Eisley South

  • 反过来,如果 Droid 中对 $scope.location 进行改写,它只改写自己scope中 location 属性的值,它不会影响 Sandcrawler 中的这个属性的值;在 view 中的表现则是:当点击了 Sell 按钮之后,两个控制器scope之间的数据共享就不复存在了,之后无论点多少次 Move 按钮,都影响不了 Droid 中的 p 标签的显示了

经过上面的教训,有时候我们想要达到的效果可能达不到(如点了 Sell 按钮之后再点 Move 还想让它起作用),这样在ng的开发者中逐渐达成了一个一致的约定,千万不要把那些可以被子级scope改写的属性用基础类型直接添加在 $scope 对象上,而是应该尽可能地用对象类型去添加。

对象类型变量的继承

通过上面的结论我们知道,可以用对象类型的变量来作为属性添加到 $scope 中去,这样,只要是引用了这个对象的,无论是谁,在哪个控制器里面,对这个对象变量的改写都会影响都所有引用了这个对象的实例。看下面的代码:

  1. function Sandcrawler($scope) {
  2. $scope.sandcrawler.location = 'Mos Eisley North';
  3. }
  4. function Droid($scope) {
  5. $scope.summon = function(newLocation) {
  6. $scope.sandcrawler.location = newLocation;
  7. }
  8. }
  9. // html
  10. <div ng-controller="Sandcrawler">
  11. <p>Sandcrawler Location: </p>
  12. <div ng-controller="Droid">
  13. <button ng-click="summon('Owen Farm')">
  14. Summon Sandcrawler
  15. </button>
  16. </div>
  17. </div>

跑一下上面的代码就知道,当我们使用“召唤术”的时候,可以改写 Sandcrawler 控制下的 p 标签的显示了。

基于event传播的方式

基于scope继承的方式只能处理父子级控制器之间的通信问题,不能处理兄弟/相邻控制器之间的通信问题。这时候,我们需要使用基于event传播的方式来进行通信,这里,ng为我们提供了三个方法:$on , $emit ,$broadcast ,需要明确的是:这种方法不仅可以处理兄弟scope间的通信问题,对于解决父子scope间的通信也是毫无压力。

子-->父:$emit

整个过程是这样的:

  • 子scope中的控制器通过 $scope.$emit 触发一个事件向上传播

  • 这个事件会经过每一层的父scope,至于处不处理是父scope自己的事情了

  • 如果处理,就在想要处理的那个祖先scope中放一个 $scope.$on 监听着就行了三四三

    1. // 父scope上的控制器
    2. function Sandcrawler($scope) {
    3. $scope.location = 'Mos Eisley North';
    4. $scope.$on('summon', function(e, newLocation) {
    5. $scope.location = newLocation;
    6. });
    7. }
    8. // 子scope上的控制器
    9. function Droid($scope) {
    10. $scope.location = 'Owen Farm';
    11. $scope.summon = function() {
    12. $scope.$emit('summon', $scope.location);
    13. }
    14. }
    15. // html
    16. <div ng-controller="Sandcrawler">
    17. <p>Sandcrawler Location: </p>
    18. <div ng-controller="Droid">
    19. <p>Droid Location: </p>
    20. <button ng-click="summon()">Summon Sandcrawler</button>
    21. </div>
    22. </div>

    如果你不想让你的事件再往更上层传播,在 $on 中的处理函数调用e.stopPropagation() 即可。

父-->子:$broadcast

从父到子,用另外一个方法就是了,同样用 $on 监听着,all done,看下面代码:

  1. // 父scope上的控制器
  2. function Sandcrawler($scope) {
  3. $scope.location = 'Mos Eisley North';
  4. $scope.recall = function() {
  5. $scope.$broadcast('recall', $scope.location);
  6. }
  7. }
  8. // 子scope上的控制器
  9. function Droid($scope) {
  10. $scope.location = 'Owen Farm';
  11. $scope.$on('recall', function(e, newLocation) {
  12. $scope.location = newLocation;
  13. });
  14. }
  15. // html
  16. <div ng-controller="Sandcrawler">
  17. <p>Sandcrawler Location: </p>
  18. <button ng-click="recall()">Recall Droids</button>
  19. <div ng-controller="Droid">
  20. <p>Droid Location: </p>
  21. </div>
  22. </div>

同级之间

拥有同个父scope的子级scope之间,也就是兄弟/相邻scope之间的通信,其实是借助“奶爸”传递消息的:

  • 子级scope中有谁想传消息了,$emit 一个给“奶爸”

  • 然后通过“奶爸” $broadcast 给所有孩子这个相同的信息,当然发出信息的那个可以选择是否要忽略掉自己发出的信息

  1. // 父scope上的控制器
  2. function Sandcrawler($scope) {
  3. $scope.$on('requestDroidRecall', function(e) {
  4. $scope.$broadcast('executeDroidRecall');
  5. });
  6. }
  7. // 子scope上的控制器
  8. function Droid($scope) {
  9. $scope.location = 'Owen Farm';
  10. $scope.recallAllDroids = function() {
  11. $scope.$emit('requestDroidRecall');
  12. }
  13. $scope.$on('executeDroidRecall', function() {
  14. $scope.location = 'Sandcrawler';
  15. });
  16. }
  17. // html
  18. <div ng-controller="Sandcrawler">
  19. <div ng-controller="Droid">
  20. <h2>R2-D2</h2>
  21. <p>Droid Location: </p>
  22. <button ng-click="recallAddDroids()">Recall All Droids</button>
  23. </div>
  24. <div ng-controller="Droid">
  25. <h2>C-3PO</h2>
  26. <p>Droid Location: </p>
  27. <button ng-click="recallAddDroids()">Recall All Droids</button>
  28. </div>
  29. </div>

上面代码中要注意的是:子scope通过 $emit 发出的事件名不能与父scope用 $broadcast 的事件名一样,如果有传参数,那当然参数可以一样,因为参数就是我们要传的数据。事件名不能一样是为了防止进入死循环。

AngularJS中控制器之间通信方法的更多相关文章

  1. angularjs中控制器之间的通信----$on、$emit和$broadcast解析

    $on.$emit和$broadcast使得event.data在controller之间的传递变的简单. $emit只能向parent controller传递event与data $broadca ...

  2. wepy中组件之间通信方法

    events events是WePY组件事件处理函数对象,存放响应组件之间通过broadcast.emit.$invoke所传递的事件的函数. $broadcast —— 父往子传 $broadcas ...

  3. AngularJS 中 Controller 之间的通信

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

  4. angularjs控制器之间通信,事件通知服务

    service要记住一点就是所有的services都是singleton(单例)的,service更多的是做一些业务逻辑,数据交互.当然,利用单例这特点也可以用来做不同控制器间的通信.控制器间的通信也 ...

  5. angularJS中控制器和作用范围

    $scope是$rootScope的子作用域控制对象,$rootScope的id为1,其他的为2,3,4... 不同的控制器之间,所对应的作用域控制对象$scope,之间是相互隔离的,如果要共享数据, ...

  6. angular中控制器之间的通讯方式

    1, 利用作用域的继承方式 由于作用域的继承是基于js的原型继承方式,所以这里分为两种情况,当作用域上面的值为基本类型的时候,修改父作用域上面的值会 影响到子作用域,反之,修改子作用域只会影响子作用域 ...

  7. AngularJS中控制器继承

    本篇关注AngularJS中的控制器继承,了解属性和方法是如何被继承的. 嵌套控制器中属性是如何被继承的? ==属性值是字符串 myApp.controller("ParentCtrl&qu ...

  8. angular中控制器之间传递参数的方式

    在angular中,每个controller(控制器)都会有自己的$scope,通过为这个对象添加属性赋值,就可以将数据传递给模板进行渲染,每个$scope只会在自己控制器内起作用,而有时候需要用到其 ...

  9. AngularJS中页面传参方法

    1.基于ui-router的页面跳转传参 (1) 用ui-router定义路由,比如有两个页面,一个页面(producers.html)放置了多个producers,点击其中一个目标,页面跳转到对应的 ...

随机推荐

  1. supercool.sh文件里,有哪些恶意的命令

    当你在一个bash命令行中输入"*"时,bash会扩展到当前目录的所有文件,然后将他们全部作为参数传递给程序.例如:rm *,将会删除掉当前目录的所有文件. 0x01 文件名被当做 ...

  2. js 获取指定日期

    查询几天后的js代码,如果查询当天的日期 if($("input[name='startTime']").val()==""){ $("input[n ...

  3. ip_conntrack table full dropping packet错误的解决方法

    ip_conntrack表满导致的,iptables开启后会加载ip_conntrack模块,来跟踪包.默认情况下ip_conntrack_max大小为65536. 查看ip_conntrack最大大 ...

  4. 如何在CentOS配置Apache的HTTPS服务

    http://www.4byte.cn/learning/120027/ru-he-zai-centos-pei-zhi-apache-de-https-fu-wu.html

  5. 记录一次Tomcat内存泄露原因的追溯

    现象:WEB无法访问.SSH无法登陆.桌面登陆验证失败. 重启服务器后登陆正常. cat /var/log/message显示root用户创建了2000多个sessions后显示内存不足. 进入tom ...

  6. GIT远程仓库地址变更

    将VS2013的解决方案添加到GIT源代码管理后会增加.gitattributes和.gitignore 2个文件以及.git目录 设置远程地址的文件在.git目录下的config文件中 直接修改上图 ...

  7. WINDOWS下PhoneGap(Cordova)安装笔记

    1.首先下载Node.js  安装nodejs很简单直接点击安装文件下一步直至成功即可,安装notejs的同时npm也会同时安装 成功后打开notejs的命令行工具 输入“node -v”," ...

  8. Google Supersonic列存储查询库的介绍、安装、测试

    查询引擎库介绍: http://www.infoq.com/cn/news/2012/10/Google-Supersonic/ Supersonic是一个面向列存储数据库的查询引擎库,它提供了一组数 ...

  9. SpringMVC常用配置-文件上传-基于Servlet 3.0

    [2] http://www.cnblogs.com/weilu2/p/springmvc_MultipartConfigElement_tomcat_webapps_work.html

  10. ASP.NET MVC location.href不跳转

    表单使用submit导致不跳转 <button type="button">