public

Complex communication between multiple AngularJs directives

Complex communication between controllers and directives (and child directives) is a common problem or challenge in large AngularJs applications (and all large MVVM applications in my opinion). It becomes even

6 years ago

Latest Post Architectural Decision Record by Tim Sommer public

Complex communication between controllers and directives (and child directives) is a common problem or challenge in large AngularJs applications (and all large MVVM applications in my opinion).
It becomes even more complicated when you have to communicate with a directive, that has an isolated scope, within a directive that has another isolated scope.

Communication with an isolated scope

When I create a directive that has an isolated scope, AngularJs provides three ways of communicating with it. I can pass in a string variable (@). I can pass in an object with two-way binding (=). Or i can pass in an external function (&).

In most cases these three options are enough. But when your directive gets bigger and more complex -possibly having multiple child directives- things can get a little tricky. If you're not careful you'll end up with a directive that resembles the example below (not a real life case, just an example :)):

<personal-calendar months="data.months"
                   dates="data.dates"
                   events="data.events" 
                   weeks="data.weeks"
                   translations="data.translations"
                   is-approver-for="isApproverFor"
                   event-click="eventClicked()"
                   event-selected="eventSelected()"
                   is-admin="isAdmin"
                   <!--and more and more and more -->
                   ng-show="hasData">
</personal-calendar>

Now, there is nothing wrong with a directive like this. It has a very clear contract that defines how a controller can access it. Which is always a good thing.

But this approach is also a lot of work and a lot of typing. If, for example, this directive has a child directive that needs the eventClicked function, you'll need to pass that function in the personalCalendar directive. And you'll have to do that for each object you want to pass along. To all children that require it.

Your code can quickly become a haystack that does nothing more than taking objects and passing them along to another object. Which becomes a nightmare when you want to refactor things.

Introducing the accessor object

I've used this approach a couple of times now, and I really love it. It really simplifies things. The idea is that you pass one object that becomes the contract. This object can then be re-used in all child directives. You'll have a lot less code-duplication and you don't need to pass individual objects.
Take a look at the following example.

We define the contract in the controller, link the functions and feed the data:

var accessor = {
     months: data.months,
     dates: data.dates,
     events: data.events,
     weeks= data.weeks,
     translations= data.translations,
     isApproverFor: isApproverFor(),
     eventClick: eventClicked,
     eventSelected: eventSelected,
     isAdmin: isAdmin
}

var self = {};
self.isApproverFor = function () { return true; };
self.eventClicked = function (event) { 
    //do something with eventClicked 
};
self.eventSelected = function (event) { 
    //do something with eventSelected 
};

And pass it along to the directive like so:

<personal-calendar accessor="accessor"
                   ng-show="hasData">
</personal-calendar>

Now we have something really powerful. The two way binding mechanism allows us to access everything defined on the accessor within the directive. Watches or event broadcasts are less necessary. You can pass this object to any child directive -and children of children- without problems, they can all use it.

Let's summarize

I've used this approach in a couple of projects now, and I really like it. But there are some cons as well. I wouldn't use it for all my directives, but once things get to complex, it is a golden approach!

Advantages

Disadvantages

Things to keep in mind when using this approach

Tim Sommer

Published 6 years ago

Comments?

Leave us your opinion.