Angularjs: sharing state between directives and their controllers

PDF

The thing with directives, controllers, scope, link and compile is: they all share keywords and concepts. This puts so much trees in front of the forest, that until you’re clear on the individual underlying concepts you have no hope of understanding the abstractions made on top of it. And so it took me a long time to understand how I can make directives/controllers share state, even if they’re not nested.

That last part is important, because in essence, you can’t share data unless you also share an ancestor. The only exception to this is if you’re using decoupled communication through events and eventlisteners.

The example we’re not doing today

Ok, let’s dive into today’s problem we’re not solving: A form with several inputs, and each one have a tooltip, except the tooltip should be displayed on a specific location, the same for all inputs. Like an information box… in fact it’s not a tooltip at all.

simple inputform with text hint

Now I’m not actually going into the code of this particular form, as it is a real world example that I’m working on that contains all kinds of stuff, like a bootstrap ui accordion and other styling that would get in the way of this example. Instead, I will treat the problem essence with the following example:

The example we are doing today

How to share state using three directives in a triangle affair

The solution is to have three directives and the trick is that one of them functions as parent scope through which the other two talk.

And here it is:

The HTML then looks like this:

How to update the text when we focus on an <input>

Ok great, we now have a way to get information accross the page into the hint box. Now how do we change it when we focus on another input box?

One thing a link function is responsible for is listening to DOM changes and reflecting this in an angular scope and then have Angular process the new value. In our case we’re listening to focus events:

That’s it, we listening to DOM events and reflecting that in Angular’s lifecycle.

Make the info directive generic by allowing us to define the event to listen to

We can even make this component more generic, by dynamically indicate the type of event which to listen to:

And the modified HTML:

All in all the HTML is very clean. Directives, although numerously enough with just the three of them, have been kept as lite as possible. Some would argue it is not a good thing to expose the entire scope in the infomanager. However, I already wished that third parent directive was not necessary, but since it is, let’s not pretend we were planning to have ‘managing behavior’ just to share this state. As far as I’m concerned, the state in the parent belongs to the underlying info and showinfo directives.

Tags:
  • Alex Hart

    That’s a great example. Totally showed me how the controller it used.

    Reply

  • Sean G. Wright

    I came up with a similar example which I posted on my github account. I wanted the parent directive to have an API that the children could plug into to allow children components to be swapped out or at least to have a loose coupling for testing and maintainability.

    I also prefer putting most of my processing for a directive in the controller function and I use the link for initialization, so my require property on the children directives is an array of two controllers, the first being ‘^parent’ and the second being ‘currentChild’, where currentChild is the name of the current child directive.

    Reply

Leave a Reply