一个控制器可以通话吗?

一个控制器可以使用另一个控制器吗?

例如:

这个HTML文档只是在messageCtrl.js文件中打印由MessageCtrl控制器传递的MessageCtrl

 <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(); }; } 

哪个只是打印当前的date;

如果我要添加另一个控制器, DateCtrl将date以特定的格式交还给MessageCtrl ,那么怎么做呢? DI框架似乎与XmlHttpRequests和访问服务有关。

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

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

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

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

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

另请观看以下video: 在控制器之间进行通信

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

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

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

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

如果你想调用另一个控制器有四种方法可用

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

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

控制器及其作用域可能被破坏,但$ rootScope保留在应用程序中,这就是为什么我们要使用$ rootScope,因为$ rootScope是所有作用域的父级。

如果你正在进行从父母到孩子的沟通,甚至孩子想与兄弟姐妹沟通,你可以使用$广播

如果你正在执行从孩子到父母的沟通,没有兄弟姐妹调用,那么你可以使用$ 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> 

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'); }); }); 

在$ emit'childEmit'的上面的代码控制台不会调用里面的兄弟姐妹,它会调用里面只有父母,其中$广播调用里面的兄弟姐妹和父母以及这是性能进入一个行动的地方$ emit是如果您正在使用从小孩到家长的沟通,因为它跳过了一些肮脏的检查。

2.如果第二个控制器是子级,则可以使用子级父级通信

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

例如HTML: –

 <div ng-controller="ParentCtrl"> <div ng-controller="ChildCtrl"> </div> </div> 

Angularjs

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

每当你使用孩子到家长的沟通,Angularjs会search儿童内部的一个variables,如果它不在里面,那么它会select看到父控制器内的值。

3.使用服务

AngularJS支持使用服务架构的“分离关注”概念。 服务是JavaScript的function,只负责完成一个特定的任务。这使得它们成为一个可维护和可testing独立实体。服务使用Angularjs的dependency injection机制注入。

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"); }); 

它会输出Hello Hello World和Hello Parent World。 根据服务的angular度文档单例 – 每个依赖于服务的组件获取对服务工厂生成的单个实例的引用

4.一些破解 – 在angular.element()的帮助下

这个方法通过它的Id / unique类获取scope()方法的ID / unique.angular.element()方法返回元素和scope()给另一个variables使用$ scopevariables的另一个variables$ scopevariables不是一个好的做法。

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> 

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

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

如果您正在寻找发送和广播事件以跨控制器共享数据或呼叫function ,请查看此链接并通过zbynour (以最大票数回答)检查答案。 我引用他的答案!

如果firstCtrl的范围是第二个控件范围的父级,那么你的代码应该在firstCtrl中用$ broadcastreplace$ 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]); } 

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

1)对于父母控制器 – 使用父控制器的$scope来发送/广播事件。 http://jsfiddle.net/laan_sachin/jnj6y/

2)在非相关的控制器上使用$rootScopehttp://jsfiddle.net/VxafF/

实际上使用发射和广播是低效的,因为事件在范围层次上下起伏,容易退化为复杂应用的性能瓶颈。

我会build议使用一项服务。 这是我最近如何在我的一个项目中实现它 – https://gist.github.com/3384419

基本理念 – 注册一个pub-sub / event bus作为服务。 然后在需要订阅或发布活动/主题的地方注入该事件总线。

我也知道这种方式。

 angular.element($('#__userProfile')).scope().close(); 

但是我不使用它太多,因为我不喜欢在angular码中使用jQueryselect器。

我不知道这是否超出标准,但是如果你把所有的控制器放在同一个文件中,那么你可以这样做:

 app = angular.module('dashboardBuzzAdmin', ['ngResource', 'ui.bootstrap']); var indicatorsCtrl; var perdiosCtrl; var finesCtrl; app.controller('IndicatorsCtrl', ['$scope', '$http', function ($scope, $http) { indicatorsCtrl = this; this.updateCharts = function () { finesCtrl.updateChart(); periodsCtrl.updateChart(); }; }]); app.controller('periodsCtrl', ['$scope', '$http', function ($scope, $http) { periodsCtrl = this; this.updateChart = function() {...} }]); app.controller('FinesCtrl', ['$scope', '$http', function ($scope, $http) { finesCtrl = this; this.updateChart = function() {...} }]); 

正如你所看到的,当调用updateCharts时,指针Ctrl正在调用其他两个控制器的updateChart函数。

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

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

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

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

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

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

 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 1上创build一个方法来使用:

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

而在directive2中,可以通过使用require选项来调用siblingController,该选项将被传递给链接函数:

 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中看到。;

这个的用法?

  • 父母:任何情况下,子元素需要与父母“注册”自己。 很像ngModel和ngForm之间的关系。 这些可以添加某些可能影响模型的行为。 你也许也有一些纯粹的基于DOM的东西,父元素需要pipe理某些孩子的位置,比如pipe理或响应滚动。

  • 兄弟姐妹:允许指令修改其行为。 ngModel是经典的例子,添加parsing器/validationngModel使用input。

以下是一个不考虑Angular JS的publish-subscribe方法。

search参数控制器

 //Note: Multiple entities publish the same event regionButtonClicked: function () { EM.fireEvent('onSearchParamSelectedEvent', 'region'); }, plantButtonClicked: function () { EM.fireEvent('onSearchParamSelectedEvent', 'plant'); }, 

searchselect控制器

 //Note: It subscribes for the 'onSearchParamSelectedEvent' published by the Search Param Controller localSubscribe: function () { EM.on('onSearchParamSelectedEvent', this.loadChoicesView, this); }); loadChoicesView: function (e) { //Get the entity name from eData attribute which was set in the event manager var entity = $(e.target).attr('eData'); console.log(entity); currentSelectedEntity = entity; if (entity == 'region') { $('.getvalue').hide(); this.loadRegionsView(); this.collapseEntities(); } else if (entity == 'plant') { $('.getvalue').hide(); this.loadPlantsView(); this.collapseEntities(); } }); 

事件pipe理器

 myBase.EventManager = { eventArray:new Array(), on: function(event, handler, exchangeId) { var idArray; if (this.eventArray[event] == null) { idArray = new Array(); } else { idArray = this.eventArray[event]; } idArray.push(exchangeId); this.eventArray[event] = idArray; //Binding using jQuery $(exchangeId).bind(event, handler); }, un: function(event, handler, exchangeId) { if (this.eventArray[event] != null) { var idArray = this.eventArray[event]; idArray.pop(exchangeId); this.eventArray[event] = idArray; $(exchangeId).unbind(event, handler); } }, fireEvent: function(event, info) { var ids = this.eventArray[event]; for (idindex = 0; idindex < ids.length; idindex++) { if (ids[idindex]) { //Add attribute eData $(ids[idindex]).attr('eData', info); $(ids[idindex]).trigger(event); } } } }; 

全球

 var EM = myBase.EventManager; 

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

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

在angular1.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({}); } } }()); 

这是父组件。 在这里我创build了一个函数,把另一个对象放到我的productForms数组中 – 注意 – 这只是我的例子,这个函数真的可以是任何东西。

现在我们可以创build另一个将使用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; }; } }()); 

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