指令之间的AngularJS通信
Posted
技术标签:
【中文标题】指令之间的AngularJS通信【英文标题】:AngularJS communication between directives 【发布时间】:2014-10-06 03:04:39 【问题描述】:我是 Angular.js 的新手,我的应用程序需要一些指令之间的通信,我阅读了一些关于链接和要求的文档,但无法准确理解它是如何工作的。
举一个简单的例子:现场小提琴:http://jsfiddle.net/yw235n98/5/
2 个指令:firstDir、secondDir :: 和一些数据 firstDir 有一个可以改变数据值的点击函数 当 firsDir 点击功能被触发时,我也想更改 secondDir 中的数据。HTML:
<body ng-app="myApp">
First Directive :
<first-dir >
<h3>firstCtrl.data</h3>
<button ng-click="firstCtrl.set('NEW VALUE')">Change Value</button>
</first-dir>
Second Directive :
<second-dir>
<h3>secondCtrl.data</h3>
</second-dir>
Javascript:
(function()
var app = angular.module('myApp', []);
app.directive("firstDir", function()
return
restrict : 'E',
controller : function()
this.data = 'init value';
this.set = function(value)
this.data = value;
// communication with second Directive ???
,
controllerAs : 'firstCtrl'
;
);
app.directive("secondDir", function()
return
restrict : 'E',
controller : function()
this.data = 'init value';
,
controllerAs : 'secondCtrl'
;
);
)();
【问题讨论】:
【参考方案1】:一种您可以使用所谓的事件在它们之间进行通信的方式。
一个指令可以在根作用域上发出一个事件,然后任何想要的人都可以收听该事件。您可以使用$rootScope.$emit
或$rootScope.$broadcast
来发布带有数据的事件,并使用$scope.$on
来监听事件。在你的情况下,你也可以做$scope.$emit
。
app.directive("firstDir", function()
return
restrict : 'E',
controller : function($scope)
this.data = 'init value';
this.set = function(value)
//EMIT THE EVENT WITH DATA
$scope.$emit('FIRST_DIR_UPDATED', value);
this.data = value;
// communication with second Directive ???
,
controllerAs : 'firstCtrl'
;
);
app.directive("secondDir", function()
return
restrict : 'E',
controller : function($scope)
var _that = this;
//LISTEN TO THE EVENT
$scope.$on('FIRST_DIR_UPDATED', function(e, data)
_that.data = data;
);
this.data = 'init value';
,
controllerAs : 'secondCtrl'
;
);
Demo Demo2
_______________________________________________________________
现在说到这一点,有时确实需要注入 $rootScope
只是为了在应用程序中为不同的节点启用事件。相反,您可以在您的应用程序中轻松构建发布/订阅机制并利用原型继承。
在这里,我在应用程序初始化期间在 $rootScope's
原型上添加 2 个方法 publish
和 subscribe
。因此,任何子作用域或隔离作用域都将拥有这些方法,并且通信将变得如此容易,而无需担心是否使用$emit
、$broadcast
,是否需要注入$rootscope
以与隔离作用域指令等进行通信。
app.service('PubSubService', function ()
return Initialize:Initialize;
function Initialize (scope)
//Keep a dictionary to store the events and its subscriptions
var publishEventMap = ;
//Register publish events
scope.constructor.prototype.publish = scope.constructor.prototype.publish
|| function ()
var _thisScope = this,
handlers,
args,
evnt;
//Get event and rest of the data
args = [].slice.call(arguments);
evnt = args.splice(0, 1);
//Loop though each handlerMap and invoke the handler
angular.forEach((publishEventMap[evnt] || []), function (handlerMap)
handlerMap.handler.apply(_thisScope, args);
)
//Register Subscribe events
scope.constructor.prototype.subscribe = scope.constructor.prototype.subscribe
|| function (evnt, handler)
var _thisScope = this,
handlers = (publishEventMap[evnt] = publishEventMap[evnt] || []);
//Just keep the scopeid for reference later for cleanup
handlers.push( $id: _thisScope.$id, handler: handler );
//When scope is destroy remove the handlers that it has subscribed.
_thisScope.$on('$destroy', function ()
for(var i=0,l=handlers.length; i<l; i++)
if (handlers[i].$id === _thisScope.$id)
handlers.splice(i, 1);
break;
);
).run(function ($rootScope, PubSubService)
PubSubService.Initialize($rootScope);
);
您可以在应用程序的任何位置发布事件,而无需 rootScope。
$scope.publish('eventName', data);
并在应用程序的任何位置收听,而不必担心使用$rootScope
或$emit
或$broadcast
:-
$scope.subscribe('eventName', function(data)
//do somthing
);
Demo - PubSub
【讨论】:
broadcast
更好,因为它向下发送事件。顺便说一句,我认为在firstDir
中,$rootScope
应该作为指令参数注入,而不是作为控制器函数中的参数
@akn 没关系,你也可以将它注入到控制器中。同样在这种情况下,您甚至不需要使用 $rootScope $scope.$emit 在性能方面更好。【参考方案2】:
我使用的是导出的指令控制器。假设我有以下指令:
app.directive('mainDirective', function ()
return
require: 'mainDirective'
restrict: 'E',
scope:
controller: '='
,
controller: [
'$scope',
function ($scope)
// controller methods
this.doSomething = function () ... ,
$scope.controller = this
return this
],
link: function (scope, element, attrs, mainDirective)
// some linking stuff
);
我的 html 看起来像这样:
<main-directive controller="mainDirective"></main-directive>
<sub-directive main-directive="mainDirective"></sub-directive>
如果我想从子指令控制主指令,我可以轻松地从它的范围中获取它并做我想做的任何事情......
app.directive('subDirective', function ()
return
restrict: 'E',
scope:
mainDirective: '='
link: function (scope, element, attrs)
// do something with main directive
scope.mainDirective.doSomething();
);
【讨论】:
这确实是一个不好的做法,因为它要求孩子们了解他们的父母,并且会让你的应用程序变得非常纠结。【参考方案3】:从您的示例中,指令结构不是父子结构。因此,您不能通过他们的控制器共享方法。我会使用$rootScope.$broadcast
。 (见DOCS)
一个指令调用:
$rootScope.$broadcast('someEvent', [1,2,3]);
第二个指令监听:
scope.$on('someEvent', function(event, mass)
console.log(mass)
);
演示Fiddle
固定指令:
app.directive("firstDir", function ($rootScope)
return
restrict: 'E',
link: function (scope, element, attrs)
scope.dataToPass = 'empty';
scope.doClick = function (valueToPass)
scope.dataToPass = valueToPass;
$rootScope.$broadcast('someEvent',
data: valueToPass
);
;
);
app.directive("secondDir", function ()
return
restrict: 'E',
link: function (scope, element, attrs)
scope.receivedData = 'none';
scope.$on('someEvent', function (event, result)
scope.receivedData = result.data;
);
);
【讨论】:
谢谢你,我在我的例子中使用了广播,因为发射没有工作。我的 2 个指令(即它们所附加的 2 个元素)直接附加到正文,并且从其中一个元素的深处调用广播。因此,根本没有父/子关系。但是根据解释,广播向下发送事件,那么它是如何工作的。最初我希望发射能够工作,但它没有。请给点灯好吗。以上是关于指令之间的AngularJS通信的主要内容,如果未能解决你的问题,请参考以下文章