1

I have custom directives like this:

<fold fold-name="Musique et sons">
    <sound-button height=60  song-name="Why Make..."></sound-button>
</fold>

fold directive has such template:

<button class="fold" ng-click="showMe = !showMe">{{foldName}} ({{nb}})</button>
<div class="fold" ng-transclude ng-show="showMe"></div>

In the sound-button controller, I have to do this:

$scope.$parent.$$prevSibling.$emit('foldstop')

If I want the controller to receive the event:

      $scope.$on 'foldplay', (sender, evt) ->

What's happening: creates 3 scopes :

 <fold> Scope
 <ng-transclude scope> which has no model, thus no controller.
      <sound-button scope> 

In sound-button directive, $scope.$emit would hit the ng-transclude scope which is a sibling of the scope I want to hit.

So I'm using $scope.$parent.$prevSibling to hit the right controller. It works, but is there a better way ?

Thanks !

John Slegers
  • 45,213
  • 22
  • 199
  • 169
user2944669
  • 165
  • 10
  • I am a little bit confused. If you want to do stuff inside fold. You can create a controller in fold and call it from sound-button when you need to. – Jesus Rodriguez Feb 01 '14 at 20:43

1 Answers1

2

You could try require if your directives are related.

app.directive('soundButton', function() {
    return {
      restrict: 'E',
      scope: {
        songName: '@'
      },
      require:"^fold", 
      link : function (scope,element,attrs,foldController){//inject fold controller 
           foldController.callFold("message"); //use the controller to communicate
      }
    };
});

app.directive('fold', function() {
    return {
      restrict: 'E',
      scope: {
        foldName: '@'
      },
      templateUrl: 'fold.html',
      transclude:true,

      controller:function(){ //declare the controller to be used by child directives.
          this.callFold = function (message){
            alert(message);
          }
      }
    };
});

DEMO

You cannot use $scope.$emit because your directives' scopes don't have parent/child relationship. You could refer to this discussion for more information.

Update:

If your directives are not related and you need to have parent/child relationship, you could try custom transclusion:

app.directive('fold', function() {
    return {
      restrict: 'E',
      scope: {
        foldName: '@'
      },
      templateUrl: 'fold.html',
      transclude:true,

      compile: function (element, attr, linker) {
          return {
           pre: function (scope, element, attr) {
             linker(scope, function(clone){ //bind the scope your self
                 element.children().eq(1).append(clone); // add to DOM
             });
           },
           post: function postLink(scope, iElement, iAttrs) {  
               scope.$on("foldplay",function(event,data){
                 alert(data);
               });
            }
          };
      }
    };
});

DEMO (click on the button and then click on the shown text)

Community
  • 1
  • 1
Khanh TO
  • 48,509
  • 13
  • 99
  • 115
  • Thanks but in my case, sometimes, sound-button has no parent fold...Moreover, the fold can be nested and the top one should also be awared that's why I need $emit. – user2944669 Feb 02 '14 at 12:00
  • @user2944669: I added 1 more solution with custom transclusion – Khanh TO Feb 02 '14 at 12:43
  • Very smart ! Between your proposal and mine (leave everything in controller but cheat in the way I call emit $scope.$parent.$prevSibling), what would be the pros / cons ? – user2944669 Feb 03 '14 at 08:26
  • @user2944669: this is to change angular's default way of creating scope hierarchy. Sorry to say that I don't know why angular does that – Khanh TO Feb 03 '14 at 09:59
  • Yes, I don't know why ng-transclude creates this sibling scope. Much of an annoyance than anything else ! – user2944669 Feb 03 '14 at 14:09
  • @user2944669: I also don't see why angular does it. People usually expect that they have child/parent relationship. – Khanh TO Feb 03 '14 at 15:11