AngularJS communication between directives
One way you can communicate between them using what is called eventing.
One directive can emit an event on the rootscope which can then be listened by anybody who wants to. You could use $rootScope.$emit
or $rootScope.$broadcast
to publish events with data and use $scope.$on
to listen to the event. In your case you could just do $scope.$emit
as well.
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'
};
});
DemoDemo2
____________________________________________________________________________
Now speaking of which, it sometimes is really required to inject $rootScope
just to have the eventing enabled to a different node in your application. You can instead have a pub/sub mechanism easily built in your app and make use of prototypical inheritance.
Here i am adding 2 methods publish
and subscribe
on $rootScope's
prototype during app initialization. So any child scope or isolated scope will have these methods available and communication will be so easier without worrying about whether to use $emit
, $broadcast
, whether i need to inject a $rootscope
for communication from isolated scoped directive etc.
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);
});
and you could just have any place from your app publish an event without requiring a rootScope.$scope.publish('eventName', data);
and listen anywhere on the application without worrying about using $rootScope
or $emit
or $broadcast
:-$scope.subscribe('eventName', function(data){
//do somthing
});
Demo - PubSub Communication between Controller and Directive in angularjs
Don't know if I got your problem but maybe this is a possible solution.
You can pass the issue as argument to your directive in this way:
app.directive("userIssues", function(){
return{
restrict: 'E',
scope: { issue: '=' },
templateUrl: 'userissues.html'
}});
and you can use it like this:
<user-issues ng-repeat="issue in issues" issue="issue"></user-issues>
Try this fiddle for an exampleHope this is what you need
AngularJS: Communication between directives
You can also do $rootScope.$broadcast events like playerStarted
. This event can be subscribed by all directives and they can react to this event by stopping themselves. The one thing that you need to do would be pass in the data about the player which is starting so that the new player does not stop itself as it too would subscribe to such event.
AngularJS: Communication between directives and view updation
emit 'model:updated
' inside scope.$apply
in myItem
directive since afterChange
is a non-angular event
Communication between directives (and other parts) in AngularJS
require
is particularly useful if you want to create custom form controls (see section Implementing custom from controls) -- i.e., you want to create your own form control with a directive. You can require
the ngModelController to get access a lot of existing functionality via its API/functions.
Another use case is found on the AngularJS home page, section Create Components, where the pane
directive uses require: '^tabs'
to get access to the tabs
controller. Since both of these components/directives create isolate scopes, scope inheritance is not an option. A service wouldn't be a good fit either, since your app could have multiple tabs
directives. So, in this case, the controller is used as a means for the pane
directive to be able to affect the tabs
scope -- to be able to get at the scope. Without using require
, the pane
directive can't get at the tabs
scope. I discuss this in more detail (with a picture) in this SO answer: 'this' vs $scope in AngularJS controllers
require
can only be used if the controller-of-interest is defined on the same element (e.g., ngModelController
), or if there is a hierarchy (e.g., pane -> tab).
Communication between unrelated directives
There is a lot of potential pitfalls when using events. For this particular case I would propose to use a service (you can bundle it with banner directive into the banner submodule).
Your directive can then register the listener to trigger banner update. Then call some updateBannerData(data)
of this service which will call the listener to trigger banner change. Here is some code directly from my head (hopefully without errors...)
.factory('bannerService', function() {
var bannerService = {
listener: null,
onUpdate(listener) {
bannerService.listener = listener;
}
updateBannerData: function(data) {
if(listener) {
listener(data);
}
}
};
return bannerService;
})
// inject bannerService here:
.directive('appBanner', [function (bannerService) {
return {
restrict: 'E',
replace: true,
controller: function ($scope) {
bannerService.onUpdate(function (data) {
// code to fetch banner from db here
});
}
};
}]);
Related Topics
How to Use a Link to Call JavaScript
Bootstrap: Open Another Modal in Modal
How to Stop Intense JavaScript Loop from Freezing the Browser
Access Properties of the Parent with a Handlebars 'Each' Loop
Initializing Select with Angularjs and Ng-Repeat
Js/Es6: Destructuring of Undefined
How to Pass JavaScript Variables as Parameters to Jsf Action Method
JavaScript Array Concat Not Working. Why
Find the Exact Height and Width of the Viewport in a Cross-Browser Way (No Prototype/Jquery)
How to Export Socket.Io into Other Modules in Nodejs
Options for Testing Service Workers via Http
How to Sort an Associative Array by Its Values in JavaScript
Cannot Set Property 'Innerhtml' of Null
Do Websockets Allow for P2P (Browser to Browser) Communication
Why Is Window (And Unsafewindow) Not the Same from a Userscript as from a <Script> Tag
Npm Start Error with Create-React-App
What's the API Key for in Google Maps API V3
How to Pull the File Name from a Url Using JavaScript/Jquery