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

例如:

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

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

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

它只是打印当前日期;

如果我要添加另一个控制器DateCtrl,它将日期以特定格式返回给MessageCtrl,将如何进行此操作?DI框架似乎与xmlhttprequest和访问服务有关。


当前回答

如果你正在寻找触发和广播事件来共享数据或跨控制器调用函数,请查看这个链接:并通过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)});
}

如果你的作用域之间没有父子关系,你可以将$rootScope注入到控制器中,并将事件广播到所有的子作用域(也就是secondCtrl)。

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

最后,当你需要从子控制器向上分派事件到作用域时,你可以使用$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]);
}

其他回答

控制器之间有多种通信方式。

最好的可能是共享服务:

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
}

另一种方法是在作用域上释放事件:

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

function SecondController($scope) 
{
  $scope.$emit('someEvent', args);
}

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

有一个方法不依赖于服务$broadcast或$emit。它并不适用于所有情况,但如果你有两个相关的控制器可以抽象成指令,那么你可以在指令定义中使用require选项。这是ngModel和ngForm最可能的通信方式。你可以使用它在嵌套的指令控制器之间通信,或者在同一个元素上。

对于父母/孩子的情况,使用方法如下:

<div parent-directive>
  <div inner-directive></div>
</div>

在父指令中,使用要调用的方法,你应该在this(而不是$scope)上定义它们:

controller: function($scope) {
  this.publicMethodOnParentDirective = function() {
    // Do something
  }
}

在子指令定义上,你可以使用require选项,这样父控制器就被传递给了链接函数(这样你就可以从子指令的作用域调用它上的函数)。

require: '^parentDirective',
template: '<span ng-click="onClick()">Click on this to call parent directive</span>',
link: function link(scope, iElement, iAttrs, parentController) {
  scope.onClick = function() {
    parentController.publicMethodOnParentDirective();
  }
}

以上内容可以在http://plnkr.co/edit/poeq460VmQER8Gl9w8Oz?p=preview上看到

兄弟指令的用法类似,但两个指令都在同一个元素上:

<div directive1 directive2>
</div>

用于在directive1上创建一个方法:

controller: function($scope) {
  this.publicMethod = function() {
    // Do something
  }
}

在directive2中,可以使用require选项调用,这将导致siblingController被传递给link函数:

require: 'directive1',
template: '<span ng-click="onClick()">Click on this to call sibling directive1</span>',
link: function link(scope, iElement, iAttrs, siblingController) {
  scope.onClick = function() {
    siblingController.publicMethod();
  }
}

这可以在http://plnkr.co/edit/MUD2snf9zvadfnDXq85w?p=preview上看到。

它的用途是什么?

Parent: Any case where child elements need to "register" themselves with a parent. Much like the relationship between ngModel and ngForm. These can add certain behaviour that can affects models. You might have something purely DOM based as well, where a parent element needs to manage the positions of certain children, say to manage or react to scrolling. Sibling: allowing a directive to have its behaviour modified. ngModel is the classic case, to add parsers / validation to ngModel use on inputs.

你可以在父控制器(MessageCtrl)中注入'$controller'服务,然后使用以下方法实例化/注入子控制器(DateCtrl): 美元的范围。childController = $controller('childController', {$scope: $scope.$new()});

现在您可以通过调用子控制器的方法来访问数据,因为它是一个服务。 如果有任何问题请告诉我。

在angular 1.5中,这可以通过以下方式实现:

(function() {
  'use strict';

  angular
    .module('app')
    .component('parentComponent',{
      bindings: {},
      templateUrl: '/templates/products/product.html',
      controller: 'ProductCtrl as vm'
    });

  angular
    .module('app')
    .controller('ProductCtrl', ProductCtrl);

  function ProductCtrl() {
    var vm = this;
    vm.openAccordion = false;

    // Capture stuff from each of the product forms
    vm.productForms = [{}];

    vm.addNewForm = function() {
      vm.productForms.push({});
    }
  }

}());

这是父组件。在这里,我创建了一个函数,将另一个对象推入我的productForms数组-注意-这只是我的示例,这个函数可以是任何东西。

现在我们可以创建另一个使用require的组件:

(function() {
  'use strict';

  angular
    .module('app')
    .component('childComponent', {
      bindings: {},
      require: {
        parent: '^parentComponent'
      },
      templateUrl: '/templates/products/product-form.html',
      controller: 'ProductFormCtrl as vm'
    });

  angular
    .module('app')
    .controller('ProductFormCtrl', ProductFormCtrl);

  function ProductFormCtrl() {
    var vm = this;

    // Initialization - make use of the parent controllers function
    vm.$onInit = function() {
      vm.addNewForm = vm.parent.addNewForm;
    };  
  }

}());

在这里,子组件创建了对父组件函数addNewForm的引用,然后可以将其绑定到HTML并像其他函数一样调用。

看这个小提琴: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>

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'];