Eka RudiAnto
Eka RudiAnto

Reputation: 61

Have two custom directives interact with each other in AngularJS

I have a two directives

angular.module('myApp.directives', []).
            directive('exampleDirective', ['version', function(version) {
             return {
                      link:function(scope,elm,attr) {
                         elm.on('click',function() {
                              //access exampleDirective2 behaviour
                         });
                      }
                    }
            }]).
            directive('exampleDirective2', ['version', function(version) {
             return {
                      link:function(scope,elm,attr) {
                         elm.on('change',function() {
                              //access exampleDirective behaviour
                         });
                      }
                    }
            }]);

As you can see on exampleDirective elm.on(click) function I want to get the exampleDirective2 function and vice versa.

Is there a way in AngularJS to achieve this?

Upvotes: 1

Views: 389

Answers (3)

link
link

Reputation: 1676

There are three solutions to this problem:

First solution: use a service

Share a service between directives, that can contain data and functions.

.service('myService', function(){
    this.data = //....
    this.function = function() //...
})

.directive('dir1', ['myService', function(myService) {
   //...
   link: function(scope, elem, attrs) {
       scope.data = myService.data;
   }
}])

The same for the other directive.

Second solution: directives' controllers

If your directives have a parent/child/sibling relationship:

.directive('dir1', function(){
    return {
        controller: function(scope, elem, attrs) {
            this.sayHello = function() {
                alert('hello')
            }
        }
    }
})

.directive('dir2', function(){
    return {
        require: '^dir1',
        link: function(scope, elem, attrs, dir1Ctrl) {
            dir1Ctrl.sayHello(); //will alert hello
        }
    }
})

However, this won't work if you directives have isolated scope. Also, depending on the relationship of the directive (parent/child or siblings) the sintax for the require attribute changes slightly; you can find more info on the AngularJS docs for directives.

Third solution: use events

You can also emit/broadcast events from the directive scopes, or inject $rootScope and use it as an event bus:

.directive('dir1', function($rootScope){
    return {   
        link: function(scope, elem, attrs) {
           var emitEvent = function(){
               $rootScope.$emit('somethingHappenedEvent', { /*you can pass optional data*/ });
           }

           emitEvent();
       }
    }
})

.directive('dir2', function($rootScope) {
    return {
        link: function(scope, elem, attrs) {
            $rootScope.$on('somethingHappenedEvent', function(event) {
                if(!event.defaultPrevented) {
                    //react to event here
                }
            })      
        }
    }
})

You could also to the same with the normal scope instead of $rootScope, but in that case you will have to keep in mind that the event will bubble up/down all the scopes (depending on the use of $emit or $broadcast). I prefer to $emit from $rootScope, to that it will be the only scope able to catch the event, and will also be quite fast.

Upvotes: 2

Pankaj Parkar
Pankaj Parkar

Reputation: 136144

If you want to do this in directive way only. Here is answer

angular.module('myApp.directives', []).
        directive('exampleDirective', ['version', function(version) {
         return {
                  link:function(scope,elm,attr) {
                     elm.on('click',function() {
                          //access exampleDirective2 behaviour
                          scope.exampleDirective2Function();
                     });
                     scope.exampleDirectiveFunction = function (){
                          //write your code here
                     }
                  }
                }
        }]).
        directive('exampleDirective2', ['version', function(version) {
         return {
                  link:function(scope,elm,attr) {
                     elm.on('change',function() {
                          //access exampleDirective behaviour
                          scope.exampleDirectiveFunction();
                     });
                     scope.exampleDirective2Function= function (){
                          //write your code here
                     }
                  }
                }
        }]);

Another way is, you can write a service, write a function in that, and use that service functions by injecting service into the directive.

Upvotes: 0

Mosho
Mosho

Reputation: 7078

One way to do this is to have a wrapper directive with a controller, which can then be shared between the directives if you use require. A simpler, and perhaps better solution (as it doesn't depend on the DOM) is to have a common service that enables communication between the directives.

Upvotes: 1

Related Questions