一个AngularJS控制器可以调用另一个吗?

Ban*_*San 575 html javascript angularjs

是否有可能让一个控制器使用另一个?

例如:

此HTML文档只是打印MessageCtrl控制器在messageCtrl.js文件中传递的消息.

<html xmlns:ng="http://angularjs.org/">
<head>
    <meta charset="utf-8" />
    <title>Inter Controller Communication</title>
</head>
<body>
    <div ng:controller="MessageCtrl">
        <p>{{message}}</p>
    </div>

    <!-- Angular Scripts -->
    <script src="http://code.angularjs.org/angular-0.9.19.js" ng:autobind></script>
    <script src="js/messageCtrl.js" type="text/javascript"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

控制器文件包含以下代码:

function MessageCtrl()
{
    this.message = function() { 
        return "The current date is: " + new Date().toString(); 
    };
}
Run Code Online (Sandbox Code Playgroud)

这只是打印当前日期;

如果我要添加另一个控制器,DateCtrl它将日期以特定格式交还给MessageCtrl,那怎么会这样做呢?DI框架似乎关注XmlHttpRequests和访问服务.

Voj*_*jta 701

如何在控制器之间进行通信有多种方法.

最好的一个可能是共享服务:

function FirstController(someDataService) 
{
  // use the data service, bind to template...
  // or call methods on someDataService to send a request to server
}

function SecondController(someDataService) 
{
  // has a reference to the same instance of the service
  // so if the service updates state for example, this controller knows about it
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是在范围上发出事件:

function FirstController($scope) 
{
  $scope.$on('someEvent', function(event, args) {});
  // another controller or even directive
}

function SecondController($scope) 
{
  $scope.$emit('someEvent', args);
}
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您也可以与任何指令进行通信.

  • 迟到了:你们确实知道你正在与使用AngularJS的Google的Vojta争论,对吧?:) (136认同)
  • 什么?为什么?所有控制器均由Angular的DI注入. (54认同)
  • 对我来说,在我的HTML中,事件发射控制器必须是监听控制器的子节点才能工作,这一点并不明显. (16认同)
  • @JoshNoe in 1 /你有两个控制器(或更多),他们都得到一个相同/共享的服务.然后,您有多种方式进行沟通,其中一些是您提到的.我会根据您的具体用例来决定.您可以将共享逻辑/状态放入服务中,并且两个控制器仅委托给该服务,甚至将服务导出到模板.当然,该服务还可以发射事件...... (7认同)
  • Hia,第一个例子要求网页知道堆栈中的所有服务.感觉就像难闻的气味(?).与第二个一样,网页是否需要提供$ scope参数? (4认同)
  • @Vojta一个控制器如何通知另一个控制器更新了服务?服务是否可以访问范围?服务是否会触发控制器侦听的事件?这些是我在查看这个答案然后尝试实现它时遇到的问题.但是,嘿,只有我,对大多数人来说,你的回答非常有帮助:) (4认同)
  • 有关事件机制的更多解释:http://stackoverflow.com/questions/14502006/scope-emit-and-on-angularjs (4认同)
  • 我错过了一些关于控制器层次结构的知识,以便使用@ Vojta的$ on/$ emit技术.我最终不得不使用$ scope.broadcast而不是$ scope.emit.请参阅此答案:http://stackoverflow.com/questions/14502006/working-with-scope-emit-and-on (2认同)

ada*_*ign 121

看到这个小提琴:http://jsfiddle.net/simpulton/XqDxG/

另请观看以下视频:控制器之间的通信

HTML:

<div ng-controller="ControllerZero">
  <input ng-model="message" >
  <button ng-click="handleClick(message);">LOG</button>
</div>

<div ng-controller="ControllerOne">
  <input ng-model="message" >
</div>

<div ng-controller="ControllerTwo">
  <input ng-model="message" >
</div>
Run Code Online (Sandbox Code Playgroud)

JavaScript的:

var myModule = angular.module('myModule', []);
myModule.factory('mySharedService', function($rootScope) {
  var sharedService = {};

  sharedService.message = '';

  sharedService.prepForBroadcast = function(msg) {
    this.message = msg;
    this.broadcastItem();
  };

  sharedService.broadcastItem = function() {
    $rootScope.$broadcast('handleBroadcast');
  };

  return sharedService;
});

function ControllerZero($scope, sharedService) {
  $scope.handleClick = function(msg) {
    sharedService.prepForBroadcast(msg);
  };

  $scope.$on('handleBroadcast', function() {
    $scope.message = sharedService.message;
  });        
}

function ControllerOne($scope, sharedService) {
  $scope.$on('handleBroadcast', function() {
    $scope.message = 'ONE: ' + sharedService.message;
  });        
}

function ControllerTwo($scope, sharedService) {
  $scope.$on('handleBroadcast', function() {
    $scope.message = 'TWO: ' + sharedService.message;
  });
}

ControllerZero.$inject = ['$scope', 'mySharedService'];        

ControllerOne.$inject = ['$scope', 'mySharedService'];

ControllerTwo.$inject = ['$scope', 'mySharedService'];
Run Code Online (Sandbox Code Playgroud)

  • 以上小提琴和视频共享服务.这是一个使用$ scope的小提琴.$ emit:http://jsfiddle.net/VxafF/ (12认同)

exc*_*lsr 52

以下是两个控制器共享服务数据的一页示例:

<!doctype html>
<html ng-app="project">
<head>
    <title>Angular: Service example</title>
    <script src="http://code.angularjs.org/angular-1.0.1.js"></script>
    <script>
var projectModule = angular.module('project',[]);

projectModule.factory('theService', function() {  
    return {
        thing : {
            x : 100
        }
    };
});

function FirstCtrl($scope, theService) {
    $scope.thing = theService.thing;
    $scope.name = "First Controller";
}

function SecondCtrl($scope, theService) {   
    $scope.someThing = theService.thing; 
    $scope.name = "Second Controller!";
}
    </script>
</head>
<body>  
    <div ng-controller="FirstCtrl">
        <h2>{{name}}</h2>
        <input ng-model="thing.x"/>         
    </div>

    <div ng-controller="SecondCtrl">
        <h2>{{name}}</h2>
        <input ng-model="someThing.x"/>             
    </div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

也在这里:https://gist.github.com/3595424

  • 是.所有Angular服务都是应用程序单例,这意味着只有一个服务实例.参考:http://docs.angularjs.org/guide/dev_guide.services.creating_services (4认同)
  • 到目前为止,我在网上看到的最好的例子.谢谢 (3认同)

Shu*_*gam 51

如果要将一个控制器调用另一个控制器,则有四种方法可用

  1. $ rootScope.$ emit()和$ rootScope.$ broadcast()
  2. 如果第二个控制器是子控制器,则可以使用父子通信.
  3. 使用服务
  4. 黑客攻击 - 在angular.element()的帮助下

1. $ rootScope.$ emit()和$ rootScope.$ broadcast()

控制器及其范围可能会被破坏,但$ rootScope仍然在整个应用程序中,这就是我们采用$ rootScope的原因,因为$ rootScope是所有范围的父级.

如果您正在进行从父母到孩子的沟通,即使孩子想要与其兄弟姐妹沟通,您也可以使用$ broadcast

如果你正在从孩子到父母进行沟通,没有兄弟姐妹调用,那么你可以使用$ rootScope.$ emit

HTML

<body ng-app="myApp">
    <div ng-controller="ParentCtrl" class="ng-scope">
      // ParentCtrl
      <div ng-controller="Sibling1" class="ng-scope">
        // Sibling first controller
      </div>
      <div ng-controller="Sibling2" class="ng-scope">
        // Sibling Second controller
        <div ng-controller="Child" class="ng-scope">
          // Child controller
        </div>
      </div>
    </div>
</body>
Run Code Online (Sandbox Code Playgroud)

Angularjs代码

 var app =  angular.module('myApp',[]);//We will use it throughout the example 
    app.controller('Child', function($rootScope) {
      $rootScope.$emit('childEmit', 'Child calling parent');
      $rootScope.$broadcast('siblingAndParent');
    });

app.controller('Sibling1', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside Sibling one');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

app.controller('Sibling2', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside Sibling two');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

app.controller('ParentCtrl', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside parent controller');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});
Run Code Online (Sandbox Code Playgroud)

在$ emit'childEmit'的上面代码控制台中不会调用子兄弟姐妹内部,它只调用父内部,其中$ broadcast也在兄弟姐妹和父母内部调用.这是性能进入行动的地方.$ emit是如果您正在使用子级到父级通信,因为它会跳过一些脏检查.

2.如果第二个控制器是孩子,您可以使用Child Parent通信

它是最好的方法之一,如果你想做孩子父母沟通,孩子想要与直接父母沟通,那么它不需要任何种类的$ broadcast或$ emit但是如果你想从父母到孩子进行沟通那么你必须使用服务或$ broadcast

例如HTML: -

<div ng-controller="ParentCtrl">
 <div ng-controller="ChildCtrl">
 </div>
</div>
Run Code Online (Sandbox Code Playgroud)

Angularjs

 app.controller('ParentCtrl', function($scope) {
   $scope.value='Its parent';
      });
  app.controller('ChildCtrl', function($scope) {
   console.log($scope.value);
  });
Run Code Online (Sandbox Code Playgroud)

无论何时使用子到父进程通信,Angularjs都会在子进程内搜索变量,如果内部不存在,则会选择查看父控制器内的值.

3.使用服务

AngularJS 使用服务架构支持"关注点分离"的概念.服务是javascript函数,只负责执行特定任务.这使得它们成为可维护和可测试单个实体.服务用于使用Angularjs的依赖注入机制注入.

Angularjs代码:

app.service('communicate',function(){
  this.communicateValue='Hello';
});

app.controller('ParentCtrl',function(communicate){//Dependency Injection
  console.log(communicate.communicateValue+" Parent World");
});

app.controller('ChildCtrl',function(communicate){//Dependency Injection
  console.log(communicate.communicateValue+" Child World");
});
Run Code Online (Sandbox Code Playgroud)

它将输出Hello Child World和Hello Parent World.根据Angular docs of services Singletons - 依赖于服务的每个组件都获得对服务工厂生成的单个实例的引用.

4.Kack of hack - 在angular.element()的帮助下

这个方法从元素中获取scope()的Id/unique class.angular.element()方法返回元素,scope()给另一个变量的$ scope变量使用另一个控制器的$ scope变量,这不是一个好习惯.

HTML: -

<div id='parent' ng-controller='ParentCtrl'>{{varParent}}
 <span ng-click='getValueFromChild()'>Click to get ValueFormChild</span>
 <div id='child' ng-controller='childCtrl'>{{varChild}}
   <span ng-click='getValueFromParent()'>Click to get ValueFormParent </span>
 </div>
</div>
Run Code Online (Sandbox Code Playgroud)

Angularjs: -

app.controller('ParentCtrl',function($scope){
 $scope.varParent="Hello Parent";
  $scope.getValueFromChild=function(){
  var childScope=angular.element('#child').scope();
  console.log(childScope.varChild);
  }
});

app.controller('ChildCtrl',function($scope){
 $scope.varChild="Hello Child";
  $scope.getValueFromParent=function(){
  var parentScope=angular.element('#parent').scope();
  console.log(parentScope.varParent);
  }
}); 
Run Code Online (Sandbox Code Playgroud)

在上面的代码控制器在Html上显示它们自己的值,当你点击文本时,你将相应地在控制台中获得值.如果你点击父控制器跨度,浏览器将控制子的值,反之亦然.


Sha*_*der 32

如果您希望发出和广播事件以跨控制器共享数据或调用函数,请查看此链接:并检查答案zbynour(以最大投票回答).我在引用他的答案!!!

如果firstCtrl的范围是secondCtrl范围的父级,那么你的代码应该通过在firstCtrl中用$ broadcast替换$ emit来工作:

function firstCtrl($scope){
    $scope.$broadcast('someEvent', [1,2,3]);
}

function secondCtrl($scope){
    $scope.$on('someEvent', function(event, mass) {console.log(mass)});
}
Run Code Online (Sandbox Code Playgroud)

如果您的范围之间没有父子关系,您可以将$ rootScope注入控制器并将事件广播到所有子范围(即secondCtrl).

function firstCtrl($rootScope){
    $rootScope.$broadcast('someEvent', [1,2,3]);
}
Run Code Online (Sandbox Code Playgroud)

最后,当您需要将子控制器中的事件调度到范围向上时,您可以使用$ scope.$ emit.如果firstCtrl的范围是secondCtrl范围的父级:

function firstCtrl($scope){
    $scope.$on('someEvent', function(event, data) { console.log(data); });
}

function secondCtrl($scope){
    $scope.$emit('someEvent', [1,2,3]);
}
Run Code Online (Sandbox Code Playgroud)


Dar*_*ght 24

另外两个小提琴:(非服务方式)

1)对于Parent-Child控制器 - 使用$scope父控制器发出/广播事件. http://jsfiddle.net/laan_sachin/jnj6y/

2)$rootScope跨非相关控制器使用. http://jsfiddle.net/VxafF/


num*_*ati 16

实际上使用发射和广播是低效的,因为事件在范围层次结构中上下波动,这很容易降级为复杂应用程序的性能瓶装.

我建议使用服务.以下是我最近在我的一个项目中实现它的方法 - https://gist.github.com/3384419.

基本思路 - 将pub-sub/event总线注册为服务.然后在需要订阅或发布事件/主题的地方注入该事件总线.


And*_*hak 5

我也知道这种方式。

angular.element($('#__userProfile')).scope().close();
Run Code Online (Sandbox Code Playgroud)

但我并没有过多使用它,因为我不喜欢在 angular 代码中使用 jQuery 选择器。

  • @zVictor,这确实是一种“不得已”的方法。它可以工作,但它超出了范围以强制您返回。这是使用 DOM 操作来强制执行某些操作,而不是以编程方式执行此操作。这很简单,它有效,但它不可扩展。 (3认同)
  • @BrianNoah,真的。可以将此代码用于原型或一些实验,但不适用于生产代码。 (2认同)