Directive Driven Development: Part 1

In a world where Web Components have become a standard and popular browsers such as Chrome and Firefox begin to support it natively, what do we tell our dear and beloved child AngularJS? Do we treat Angular like the long forgotten step-child of Javascript development, letting it die a legacy death into the world of Myspace (only to be remembered as a way to hack HTML), or do we evolve our thinking in how we use and structure our code with such a phenomenal framework?

Today, I am proposing that we educate ourselves as developers with a more sustainable and maintainable approach to Angular development. We need to stop dressing Angular in tank tops with sandals and realize that Angular is ready for a skinny tie and slacks. It's time that we ditch our love of ng-controller, which litters itself all over our templates, and muscle through the pain and sweat of angular.module().directive().

The solution: Directive Driven Development. In the first of this two part series, we're going to look at the what, how and why of Directive Driven Development. In part two, we'll dive deeper into DDD with a video where we'll refactor an Angular app using the DDD methodology.

What Is Directive Driven Development?

Directive Driven Development isn't anything fancy or new, it's just a way to reshape our thinking in this awkward Web Component world (I say awkward because I still can't get the taste of XML out of my mouth). With the likes of Polymer and React, the idea of loosely coupled, self-contained functionality has proven that custom elements are here to stay.

How Do I Use Directive Driven Development?

Directive Driven Development is the simple idea that you define your app's functionality through directives instead of basic HTML tags with ng-controller attributes.

(Aside: this article is by no means an extensive look into creating custom directives. For a detailed guide to custom Angular directives see Creating Custom AngularJS Directives Part I – The Fundamentals.)

For example:

my-element.js

angular.module('myApp')
  .directive('myElement', function () {
    return {
      controller: function ($scope) {
        $scope.foo = 'bar';
      },
      template: '<div>{{foo}}</div>'
    };
  });

index.html

<my-element></my-element>

Instead of:

app.js

angular.module('myApp')
  .controller('myElementController', function ($scope) {
    $scope.foo = 'bar';
  });

index.html

<div ng-controller="myElementController">{{foo}}</div>

Please note that the goal is not to reduce the number of characters you type, but to contain a certain set of functionality in a single location. Sometimes, defining directives proves to be a bit more code in the end.

The Breakdown on Why DDD Is Better

Notice how all of our functionality for a specific area of code is located in the directive:

angular.module('myApp')
  .directive('myElement', function () {
    return {
      controller: function ($scope) {
        $scope.foo = 'bar';
      },
      template: '<div>{{foo}}</div>'
    };
  });

This is the fundamental concept behind Web Components and frameworks like Polymer and React. "Shove it all in there so I don't have to look at it". It also solves one of the greatest headaches of large-scale Angular applications: "WHERE DO I FIND WHATEVER THIS IS ATTACHED TO!?"

For example, notice how this element has the ng-controller attribute:

<div ng-controller="myElementController"></div>

Where do I even begin to look for that controller? I CAN'T FIND IT!

I can't find it!

Controllers Aren't All That Bad

I'm not saying that defining controllers on their own are a bad thing. A very powerful piece of Angular is the ability to reuse things like controllers across multiple areas of your application. What I would like to drive home though is that you should make every effort to contain these controllers within a directive and not litter your templates or index.html with ng-controller.

What Your App Will Look Like With DDD

Once you've exposed parts of your application's functionality as directives, here's how your index.html might look:

<user-list users="{{users}}">
  <user-item user="{{user}}" ng-repeat="{{user in users}}">
    <h1>{{user.name}}</h1>
    <img ng-href="{{user.avatar}}" />
  </user-item>
</user-list>

NIIICE!!!

In order to use these directives as custom elements, it would be as simple as defining directives for:

  • <user-list>
  • <user-item>

Each of these directives would handle itself, with no need to worry about "where's my controller?" or "where's my templates?". Don't you see the beauty!? Even though these look like Web Components, it's still Angular. Angular grown up, wearing a skinny tie and pair of slacks. Angular written with Directive Driven Development.

But What About...?

  • How do I use Directive Driven Development in my app?
  • Can I still use controllers?

Those are very good questions! We'll tackle them in part two of this series when we take a normal Angular app and DDDify it.

Stay tuned!