Reputation: 13367
I have this directive (which I will cut down for brevity):
.directive('simpleConfigurator', function () {
return {
restrict: 'A',
scope: {
garment: '=simpleConfigurator',
colours: '=',
onComplete: '&'
},
require: ['designs', 'colours'],
transclude: true,
templateUrl: '/assets/tpl/directives/kit.html',
link: function (scope, element, attrs, controllers) {
scope.svgPath = 'assets/garments/' + scope.garment.slug + '.svg';
// Executes after the svg has loaded
scope.loaded = function () {
scope.$broadcast('loaded', { loaded: true });
};
}
};
})
The HTML for this looks like this:
<div ng-transclude></div>
<div id="{{ garment.slug }}" ng-include="svgPath" onload="loaded()"></div>
I am trying to get it to communicate with other directives. So in my designs directive, I have this:
.directive('designs', function () {
return {
restrict: 'A',
controller: 'ConfiguratorDesignsDirectiveController',
link: function (scope) {
scope.$on('loaded', function () {
console.log('we have loaded');
});
}
}
})
I was hoping that I would get a console log stating we have loaded but I didn't. I assume it is because both "designs" and "colours" are considered the parents and the child is the directive that requires them.
Is there another way I can communicate with the parent directives or is there a way to get this to work?
Upvotes: 0
Views: 108
Reputation: 22577
Your simpleConfigurator
directive has its own isolate scope. You can see using console.log(scope)
that scopes of simpleConfigurator
and design
directives are different. So when you broadcast from simpleConfigurator
it never reaches design
. Here is an article explaining this in detail.
http://www.bennadel.com/blog/2725-how-scope-broadcast-interacts-with-isolate-scopes-in-angularjs.htm
How to communicate between directives - I have found this article very helpful.
http://blog.dudak.me/2014/angular-js-directive-communication-guide-part-1/
In your case you can perhaps use this strategy -
app.directive("server", function() {
return {
controller: function() {
this.log = function(message) {
console.log(message);
};
}
};
});
app.directive("client", function() {
return {
require: "^server",
link: function($scope, $elem, $attrs, serverCtrl) {
serverCtrl.log("Hello, this is the client!");
}
};
});
You might want to use the DOM load event inside the link function - The load event is fired when a resource and its dependent resources have finished loading.
elem.addEventListener('load', callbackFunction, false)
Upvotes: 0
Reputation: 1377
Injecting the $rootScope
and using $rootScope.$broadcast
I believe is what you are trying to do although this isn't the ideal solution.
It may be better to use a form of pub/sub architecture between your parent controller and directives then make use of the $rootScope
from your controller.
You can always pass event names to your directive that it can listen out for through attributes. Make use of $scope.$emit
and $scope.$on
to get this working how you desire.
This will promote the DRY principle and aim to make your directive more generic and reusable across your application which is one of the intentions with directives in general.
Hope that helps you out!
Upvotes: 0
Reputation: 33171
You have a couple of options:
You could inject $rootScope
, and broadcast from there. Although this should work, it wouldn't be my first choice.
You can also use a controller on your parent directive, and pass that to the child directives, using it as a communication medium. It looks like you already have the controller setup. So instead of using $on
inside the directive, why not forgo events all together. Just call a function on your controller.
This is also definitely relevant: What's the correct way to communicate between controllers in AngularJS?
Upvotes: 1
Reputation: 9597
Another possible problem here could be that simpleConfigurator
is rendered before designs
. So, the event is broadcast before any listeners are set up.
You could try requiring the parent directive in your child directive and then you'd have access to the parent controller:
In simpleConfigurator
:
return {
restrict : 'E',
require : '^designs',
link : function (scope, elem, attrs, designsController) {
designsController.doStuff();
}
}
In designs
:
return {
restrict : 'E',
controller : function ($scope) {
$scope.doStuff = function () {
// do some stuff
}
}
};
Upvotes: 0