4

I've created 2 directives: Parent and Child. Trying to get them to talk to one another. It seems if they both have a scope they don't receive the events. This doesn't seem correct according to the documentation which $emit states: Dispatches an event name upwards through the scope hierarchy notifying the registered ng.$rootScope.Scope#methods_$on listeners.

So surely that should bubble up through scopes?

http://plnkr.co/edit/WNqN4XZKaLAvBEtSyERA?p=preview

creamcheese
  • 2,524
  • 3
  • 29
  • 55

2 Answers2

6

The problem is with you parent/child assumption:

  • Parent is only a parent element of Child but not a parent scope.
  • Actually they are sibling scopes, both children of the $rootScope ($id: 002) in this case.

Why??

  • Due to this commit, Isolate scope is now available only to the isolate directive that requested it and its template.
  • It means that parent directive contents (which included the child directive) are still linked to the outer scope.
  • So the child directive creates isolated scope which is a child of the outer scope.
  • Neither $emit nor $broadcast would work with sibling scopes.

enter image description here


Solution:

here is a plunker: http://plnkr.co/edit/EfKJthkQLitWnF2srykM?p=preview

You can create the child directive as a template of the parent directive, because template directives do get the directive's scope as mentioned above.

.directive('parent', function ($timeout) {
  return {
    template:'<child name="Jimmy"></child>',

do you really need the event bus?

Another solution would be to create a controller on the parent directive and to require it in child directives.

.directive('parent', function ($timeout) {
  return {
    controller: function(){
      this.hungry = function(message){
        // something
      }
    }

child directive:

.directive('child', function ($timeout) {
  return {
    require: "^parent",
    link: function (scope, element, attrs, parentCtrl) {

       parentCtrl.hungry("I'm hungry!")
Ilan Frumer
  • 32,059
  • 8
  • 70
  • 84
  • Damn, that's quite unexpected. In my mind I was thinking of events like DOM events where they bubble up the DOM. I can imagine many people fall for this trap. The reason I thought events were the solution is because The child doesn't require the parent to function, I wanted to emit events for other directives to listen if they want to know the result of a calculation as they require the child to function for what he knows. I'm guessing I need to pass in data from the outside, alter it and watch inside the parent directive for the change. Thanks for the detailed explanation :) – creamcheese Jan 28 '14 at 11:21
  • You can also use `require: "?^parent"` to optionally require a parent directive's controller. From [$compile docs](http://docs.angularjs.org/api/ng.$compile): *Attempt to locate the required controller by searching the element's parents or pass null to the link fn if not found.* – Ilan Frumer Jan 28 '14 at 11:25
1

In your example both directives have isolated scopes from the same parent scope, so they do not have parent/child relationship.

To get it work as you expected you may specify scope: true instead of scope: {...}. In this case the scope of child directive will be really child scope of parent directive's scope.

see the plucker

GRaAL
  • 616
  • 3
  • 14