I'am new to Angular.js, I need for my application some communication between directives, I read some documentation about link and require, but can't understand exactly how it works.
For a simple example I have : live fiddle : http://jsfiddle.net/yw235n98/5/
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'
};
});
})();
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'
};
});
____________________________________________________________________________
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
});
From your example the directive structure is not parent-child. Therefore you can't share methods through their controllers. I would use $rootScope.$broadcast
. (See DOCS )
One directive calls:
$rootScope.$broadcast('someEvent', [1,2,3]);
Second directive listens:
scope.$on('someEvent', function(event, mass) {
console.log(mass)}
);
Demo Fiddle
Fixed directives:
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;
});
}
}
});
What I'm using is exported directive controller. Let's say I have following directive:
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
}
}
});
My html would look something like this:
<main-directive controller="mainDirective"></main-directive>
<sub-directive main-directive="mainDirective"></sub-directive>
If I wanted to control main-directive from sub-directive I can easily grab it from it's scope and do whatever I want...
app.directive('subDirective', function () {
return {
restrict: 'E',
scope: {
mainDirective: '='
}
link: function (scope, element, attrs) {
// do something with main directive
scope.mainDirective.doSomething();
}
}
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.