Component-based Directives in AngularJS

By: Matias Niemelä

matias[at]yearofmoo[dot]com

Slides & Code

Slides: yom.nu/angular-scrapbook-slides

Code: yom.nu/angular-scrapbook-code

Controllers & Directives in AngularJS

Controllers and Directives make up an Angular App

Controllers -> logic

Directives -> DOM stuff

Controllers: The Basics

We use controllers to manage logic in an app

Controllers are attached to a template

All inputs and outputs => handled via controller functions

We should always use Controller As

Controllers: Demo

<script> angular.module('App', []) .controller('NewsController', function() { this.title = 'Welcome'; this.description = '... hi there ...'; }) </script> <div ng-controller="NewsController as newsCtrl"> <h3>{{ newsCtrl.title }}</h3> <p>{{ newsCtrl.description }}</p> </div>

Directives: The Basics

Directives supercharge the power of HTML

NgRepeat, ngIf, ngModel, etc…

We can also create custom directives

<component>, <div component>, <div class="component"></div>

Directives: Demo

<script> angular.module('App', []) .directive('counter', function() { return function(scope, element) { var count = 0; function update() { element.html(count++); } update(); element.on('click', update); }; }); </script> <counter></counter>

So what needs to be fixed?

We want to start using more directives

Why fix something that isn’t broken?

You’ll see when you start building a bigger app

This is the direction that 2.0 is going

Controllers are too general

As our application grows…

Then controllers get too big

Controllers take on too much stuff

Controllers are not reusable

Controllers Demo (general)

ngModule.controller('HomePageController', function() { var ctrl = this; this.users = [...]; this.news = [...]; $http.get('/api/comments').success(function(comments) { ctrl.comments = comments; }); this.removeComment = function() { ... }; this.submitComment = function() { ... }; this.setTab = function() { ... }; });

Controllers are limited

Even though the logic/DOM separation is great

Controllers are just half baked directives

It’s hard to read attributes

And it’s not encouraged to modify the DOM

Controllers rely too much on the template

Controllers end up special casing the template

Setters + Getters? Or just properties on the controller?

Why test something so customized?

But we can still use multiple controllers

ng-controller=“CtrlA” does the job

But it’s difficult to share data

And setup a dependency between controllers

Controllers Demo (multiple ctrls)

<div ng-controller="AController as aCtrl"> <div ng-controller="BController as bCtrl" parent-sum="aCtrl.sum"> {{ productSum }} </div> </div> <script> ngModule.controller('BController', function($attrs, $scope) { this.productSum = 10 * $scope.$eval($attrs.parentSum); }); </script>

Directives are more powerful

Why not just use more directives

And let the HTML code wire things up

We can still include controllers in the code

But we can leverage the best of what directives do

Directives are specific but reusable

<calendar-component> does what?

We can track all of the attributes

And define the HTML code to do what we want

Directives Demo (specific)

<calendar month="page.month"> <calendar-toggle options="month, day, year"></calendar-toggle> <calendar-cell ng-repeat="day in calendarCtrl.days"> {{ day.number }} </calendar-cell> </calendar>

Directives are template-friendly

Directives can load a remote template

And they can transclude an inner template

Or duplicate an existing template

Directives are good for unit tests

We have things to test!

With custom directives we can mock out HTML

Snippets of HTML == Inputs for the directive

With controllers we have to test out the entire app

The plan for Angular 2.0

RIP Scope & Controller

Directives = Components

Components = Directives with DI & Controllers

AngularDart already does this

When not to use Directives

We use directives within templates

But we still use controllers for routing

Remember to use controllerAs for routes

Getting Started

It’s OK to still build an angular app normally

But we want to directify the HTML code afterwards

And then refactor + test it

Code, Directify, Refactor, Test

A Quick Demo

Let's see a live example with a HTML grid

Example: An Angular Scrapbook

https://github.com/yearofmoo/angular-scrapbook

First we build everything

Then we refactor and test

Then we party

Stage 1 - The application

So we have an application

That collects links and data from the internet

And posts it all as a scrapbook

Let’s see the code

What’s good?

Not too big of an app

The form code looks great

The application is straight-forward

Any room for growth?

What happens if we want to have special posts?

That render different content per post?

So what happens when we extend things?

HTML overload

The more branching we do...

The bigger the HTML files get

We should use directives to break things apart

Directive 1 - Scrapbook Post

Our first directive => <scrapbook-entry>

This should render the scrapbook item

Directive 1 - Code

Let's take a look at the code

Directive 1 - Transclude

What if we want to render out the content?

Transclusion allows our own template to operate within

We should always split data from presentation

Directive 1 - Don’t go too far

Our code still works with other directives

This is why it’s important to use regular markup first

And then to refactor when things get complex

Bottom Line: Simplify

Directive 2 - Scrapbook Form

We should make the form reusable

We should also separate the data from the form itself

Directive 2 - Code

Let's take a look at the code

Testing it out

To test this we need to compile the HTML

And then test the boundaries of the code

Thank you sir

Name: Matias Niemelä

Twitter: @yearofmoo

Website: www.yearofmoo.com

Email: matias [at] yearofmoo [dot] com