[英]Can one AngularJS controller call another?
是否可以讓一個控制器使用另一個控制器?
例如:
這個 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();
};
}
它只是打印當前日期;
如果我要添加另一個控制器DateCtrl
,它將特定格式的日期交回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/
另請觀看以下視頻:控制器之間的通信
網址:
<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'];
如果您想將一個控制器調用到另一個控制器,有四種方法可用
1. $rootScope.$emit() 和 $rootScope.$broadcast()
控制器及其作用域可能會被破壞,但 $rootScope 仍然存在於整個應用程序中,這就是我們采用 $rootScope 的原因,因為 $rootScope 是所有作用域的父級。
如果您正在執行從父母到孩子的交流,甚至孩子也想與其兄弟姐妹交流,您可以使用 $broadcast
如果您正在執行從孩子到父母的通信,沒有兄弟姐妹 invovled 那么您可以使用 $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' 代碼控制台不會調用內部子兄弟姐妹,它只會在父內部調用,其中 $broadcast 在兄弟姐妹和父內部也被調用。這是性能發揮作用的地方。 $emit 是更可取的是,如果您使用子級到父級的通信,因為它會跳過一些臟檢查。
2.如果Second controller是child,可以使用Child Parent通信
它是最好的方法之一,如果你想在孩子想要與直接父母交流的情況下進行孩子父母的交流,那么它不需要任何類型的 $broadcast 或 $emit 但如果你想從父母到孩子進行交流,那么你必須使用 service 或 $broadcast
例如 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 都會在子級內部搜索變量,如果內部不存在該變量,則它將選擇查看父級控制器內部的值。
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");
});
它將給出輸出 Hello Child World 和 Hello Parent World 。 根據服務單例的Angular 文檔- 依賴於服務的每個組件都獲得對服務工廠生成的單個實例的引用。
4.Kind of hack - 在 angular.element() 的幫助下
此方法通過元素的 Id / 唯一 class.angular.element() 方法從元素獲取 scope() 方法返回元素,並且 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>
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 上顯示自己的值,當您單擊文本時,您將在控制台中獲得相應的值。如果您單擊父控制器跨度,瀏覽器將控制子控制器的值,反之亦然。
這是兩個控制器共享服務數據的一頁示例:
<!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
如果您希望發出和廣播事件以在控制器之間共享數據或調用函數,請查看此鏈接:並檢查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]);
}
還有兩個小提琴:(非服務方法)
1) 對於父子控制器 - 使用父控制器的$scope
來發出/廣播事件。 http://jsfiddle.net/laan_sachin/jnj6y/
2) 跨非相關控制器使用$rootScope
。 http://jsfiddle.net/VxafF/
實際上使用發射和廣播是低效的,因為事件在范圍層次結構中上下冒泡,這很容易降低復雜應用程序的性能瓶頸。
我建議使用服務。 這是我最近在我的一個項目中實現它的方式 - https://gist.github.com/3384419 。
基本思想 - 將發布訂閱/事件總線注冊為服務。 然后在需要訂閱或發布事件/主題的地方注入該事件總線。
我也知道這種方式。
angular.element($('#__userProfile')).scope().close();
但是我並沒有過多使用它,因為我不喜歡在 angular 代碼中使用 jQuery 選擇器。
有一種不依賴於服務的方法, $broadcast
或$emit
。 它並不適用於所有情況,但如果您有 2 個可以抽象為指令的相關控制器,那么您可以在指令定義中使用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 上創建方法來使用:
controller: function($scope) {
this.publicMethod = function() {
// Do something
}
}
在指令 2 中,這可以通過使用require
選項調用,這會導致兄弟控制器被傳遞給鏈接函數:
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 的東西,其中父元素需要管理某些子元素的位置,比如管理滾動或對滾動做出反應。
兄弟:允許指令修改其行為。 ngModel 是經典案例,將解析器/驗證添加到 ngModel 對輸入的使用。
我不知道這是否超出標准,但是如果您將所有控制器都放在同一個文件中,那么您可以執行以下操作:
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 時,指標控件正在調用其他兩個控制器的 updateChart 函數。
您可以在父控制器(MessageCtrl)中注入“$controller”服務,然后使用以下方法實例化/注入子控制器(DateCtrl):
$scope.childController = $controller('childController', { $scope: $scope.$new() });
現在您可以通過調用其方法來訪問來自您的子控制器的數據,因為它是一項服務。
如果有任何問題,請告訴我。
以下是一種與 Angular JS 無關的publish-subscribe
方法。
搜索參數控制器
//Note: Multiple entities publish the same event
regionButtonClicked: function ()
{
EM.fireEvent('onSearchParamSelectedEvent', 'region');
},
plantButtonClicked: function ()
{
EM.fireEvent('onSearchParamSelectedEvent', 'plant');
},
搜索選擇控制器
//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();
}
});
事件管理器
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;
在 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 並像任何其他函數一樣調用。
您可以使用 AngularJS 提供的$controller
服務。
angular.module('app',[]).controller('DateCtrl', ['$scope', function($scope){
$scope.currentDate = function(){
return "The current date is: " + new Date().toString();
}
}]);
angular.module('app').controller('MessageCtrl', ['$scope', function($scope){
angular.extend(this, $controller('DateCtrl', {
$scope: $scope
}));
$scope.messageWithDate = function(message){
return "'"+ message + "', " + $scope.currentDate;
}
$scope.action2 = function(){
console.log('Overridden in ChildCtrl action2');
}
}]);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.