到目前为止,我已经看到了许多问题的解决方案。当然,最简单的一个是$emit
$rootScope
中的事件作为事件总线,例如(https://github.com/btilford/anti-patterns/blob/master/angular/Angular.md)
angular.module('myModule').directive('directiveA', function($rootScope) {
return {
link : function($scope, $element) {
$element.on('click', function(event) {
$rootScope.$emit('directiveA:clicked', event);
});
}
}
});
angular.module('myModule').directive('directiveB', function() {
return {
link : function($scope, $element) {
$rootScope.on('directiveA:clicked', function(event) {
console.log('received click event from directiveA');
});
}
}
});
另一个是使用mediator或pubsub功能/封闭范围声明服务,例如(Communicating between a Multiple Controllers and a directive。)
module.factory('MessageService',
function() {
var MessageService = {};
var listeners = {};
var count = 0;
MessageService.registerListener = function(listener) {
listeners[count] = listener;
count++;
return (function(currentCount) {
return function() {
delete listeners[currentCount];
}
})(count);
}
MessageService.broadcastMessage = function(message) {
var keys = Object.keys(listeners);
for (var i = 0; i < keys.length; i++) {
listeners[keys[i]](message);
}
}
return MessageService;
}
);
问题是:
答案 0 :(得分:15)
在编写AngularJS应用程序时,创建自己的事件发射器实现会产生反作用。 Angular已经提供了基于事件的通信所需的所有工具。
$emit
上使用$rootScope
可以很好地进行全球跨服务通信,并且没有任何缺点。$broadcast
提供视图组件(指令,控制器)之间的范围通信。$broadcast
上使用$rootScope
将前两个点合在一起(它提供了一个完全全球化的通信平台)。 这是基本上由任何基于AngularJS的库使用的解决方案。 和
$rootScope.$new(true)
)并使用$broadcast
轻松创建一个它。 (然后,您可以将其包装到服务中并将其注入任何您想要的位置。)最后一个选项创建了一个集成到Angular中的完整事件发射器(您的问题中提供的实现至少需要包含$apply()
中的所有侦听器调用以进行正确集成),这些调用可以另外用于数据更改观察,如果符合特定的用例。
但是,除非您的申请真的很大,或者您对事件名称冲突真的很偏执,否则前三个选项就足够了。
我不会详细介绍组件之间的其他通信方式。一般来说,当情况需要使用范围,控制器的直接交互或通过DOM节点属性进行通信来进行数据共享时,您应该知道它。
答案 1 :(得分:10)
我想说广播是一种角度方式如何实现这一点。
但是你的中介可以工作,如果你传递指令的内部功能,例如我在范围内使用了方法,但也可以用控制器方法完成。
我使用了与您发布完全相同的工厂。
angular.module("sharedService", [])
.factory('MessageService',
function() {
var MessageService = {};
var listeners = {};
var count = 0;
MessageService.registerListener = function(listener) {
listeners[count] = listener;
count++;
return (function(currentCount) {
return function() {
delete listeners[currentCount];
};
})(count);
};
MessageService.broadcastMessage = function(message) {
var keys = Object.keys(listeners);
for (var i = 0; i < keys.length; i++) {
listeners[keys[i]](message);
}
};
return MessageService;
}
)
.directive("directiveA", function(MessageService) {
return {
link:function(scope) {
scope.click = function() {
MessageService.broadcastMessage("broadcasted message");
};
},
template: '<button ng-click="click()">Click</button>'
};
})
.directive("directiveB", function(MessageService) {
return {
link:function(scope) {
scope.callback = function(message) {
console.log(message);
};
MessageService.registerListener(scope.callback);
}
};
});
完整示例:http://jsbin.com/mobifuketi/1/edit?html,js,console,output
为了完成,我想补充一点,角度也提供了更多的可能性,指令如何沟通。
需要属性
如果您的指令在层次结构中连接,那么您可以使用require属性来访问其他指令控制器。对于许多情况来说,这是最好的解决方案。
.directive("directiveA", function() {
return {
require: "^directiveB",
link: function(scope, element, attrs, directiveCtrl) {
scope.click = function() {
directiveCtrl.call();
};
},
template: '<button ng-click="click()">Click</button>'
};
})
.directive("directiveB", function() {
return {
controller :function() {
this.call = function() {
console.log("method has been called");
};
}
};
});
完整示例:http://jsbin.com/turoxikute/1/edit?html,js,console,output
使用$ watch
如果功能取决于数据而不取决于操作,那么您将使用$ watch并对存储在共享服务中的给定模型或模型的更改做出反应,它不像监听器,它基本上检查更改。我命名方法changeState()和log&#34;状态已更改&#34;因为每个人都看得很清楚。
angular.module("sharedService", [])
.service("MediatorService", function() {
this.state = true;
this.changeState = function() {
this.state = !this.state;
};
})
.directive("directiveA", function(MediatorService) {
return {
link:function(scope) {
scope.click = function() {
MediatorService.changeState();
};
},
template: '<button ng-click="click()">Click</button>'
};
})
.directive("directiveB", function(MediatorService) {
return {
link:function(scope) {
scope.mediator = MediatorService;
scope.$watch("mediator.state", function(oldValue, newValue) {
if (oldValue == newValue) {
return;
}
console.log("state changed");
});
}
};
});
完整示例:http://jsbin.com/darefijeto/1/edit?html,js,console,output
答案 2 :(得分:3)
我喜欢活动巴士。
Angular确实在$ rootScope上提供了$ emit,但我不认为如果它们复杂或可预见的复杂,那么你决定将它用于基于事件的流。 Angular有很多功能,虽然大多数都很棒,但即使作者承认它们主要是为了恭维良好的软件工程原理,而不是取代它们。
我喜欢这篇关于使用postal.js:An angular.js event bus with postal.js的帖子。两个主要的好处是通道和包络,这将使更明确,可理解和灵活的基于事件的逻辑。
如果状态未得到严密管理,我发现基于服务的方法容易出错,这对于异步调用和注入很难实现,在这种情况下,您无法确定服务将来如何实现多用途。