12

I already know that you can set up a controller within a directive, and that other directives can call the functions on that controller. Here's what my current directive looks like:

app.directive("foobar", function() {
  return {
    restrict: "A",
    controller: function($scope) {
      $scope.trigger = function() {
        // do stuff
      };
    },
    link: function(scope, element) {
     // do more stuff
    }
  };
});

I know that I could call it like this:

app.directive("bazqux", function() {
  return {
    restrict: "A",
    require: "foobar",
    link: function(scope, element, attrs, fooBarCtrl) {
        fooBarCtrl.trigger();
    }
  };
});

However, I want to be able to call trigger from any directive, not just my own custom ones, like this:

<button ng-click="foobar.trigger()">Click me!</button>

If that doesn't work, is there a way to bring in a third directive to make it happen? Like this?

<button ng-click="trigger()" target-directive="foobar">Click me!</button>

Thanks!

3 Answers3

8

Sounds like you need an angular service. http://docs.angularjs.org/guide/dev_guide.services

This will allow you to share functionality across directives.

Here's a similar question: Sharing data between directives

Community
  • 1
  • 1
Mathew Berg
  • 28,625
  • 11
  • 69
  • 90
  • I've used services, but I have no idea how I'd use them to facilitate cross-directive communications. Can you provide an example? – Raphie Palefsky-Smith May 18 '13 at 20:46
  • Sure, can you dump both your directives that need to be communicated with one another in a jsfiddle? – Mathew Berg May 18 '13 at 23:24
  • 2
    I would not use the rootScope method if that's what you're doing. I posted an edit to my question that shows a similar question asked. – Mathew Berg May 19 '13 at 14:31
  • It would be great to see an example which does it like in this post: http://fdietz.github.io/recipes-with-angular-js/directives/directive-to-directive-communication.html but without the need of an attribute, but instead with an own directive. – Robin Wieruch Dec 28 '14 at 12:20
  • An issue here is it's a singleton like which is what service are in Angular. If you want to keep the data isolated to the area in the application, you might consider using a master controller for the area of the application you're in with isolated scope and 'require' attribute from the children referring that controller. It might be more tightly coupled but it defines an API through a controller and you can have multiple instances of the same directive not sharing their state. [See example](http://blog.carbonfive.com/2015/03/25/communication-between-collaborating-directives-in-angular/). – Gabriel Kohen Jul 06 '15 at 15:34
6

One simple way of accomplishing application-wide communication between any components would be to use global events (emitted from the $rootScope). For example:

JS:

app.directive('directiveA', function($rootScope)
{
    return function(scope, element, attrs)
    {
        // You can attach event listeners in any place (controllers, too)

        $rootScope.$on('someEvent', function()
        {
            alert('Directive responds to a global event');
        });
    };
});

HTML:

<button ng-click="$emit('someEvent')">Click me!</button>

Here you're emitting an event from the child scope but it will eventually reach the $rootScope and run the previous listener.

Here's a live example: http://plnkr.co/edit/CpKtR5R357tEP32loJuG?p=preview

mirrormx
  • 4,049
  • 1
  • 19
  • 17
  • 4
    Don't do this, it will pollute rootscope, create a service or maybe require the directive. – Willem D'Haeseleer Apr 03 '14 at 08:15
  • pointing out `$rootScope` gotchas: http://jsfiddle.net/drzaus/a1gm7q4u/ basically like @WillemD'haeseleer said, you may get side effects sending things up to / down from `$rootScope` if other "isolated" scopes are listening to the same thing (i.e. repeated directive or controller) – drzaus Oct 16 '14 at 20:16
  • Agreed, downvoted because this answer is accepted but is not as good as some of the others. – Ed_ Dec 11 '14 at 11:38
1

When talking on irc it turned out that the communication is unnecessary:

I've got an attribute-restricted directive which performs some DOM manipulation on its parent element when it's "triggered"

A solution is to keep the logic inside the same directive and just to apply the dom changes to the parent. http://jsfiddle.net/wt2dD/5/

scope.triggerSmthOnParent = function () {
    element.parent().toggleClass('whatewer');
}
edzis
  • 88
  • 4