The Code Dump

A place a coder rants at...

Angular Performance: ng-show vs ng-if

| Comments

You’ve probably come across ng-if and ng-show and wondered why they both exist and what’s the difference between them. After all they usually have the same behavior as far as the user is concerned.

The devil is in the details and the differences between these directives can allow your to boost your application’s performance easily.

The Differences

Both ng-show and ng-if receive a condition and hide from view the directive’s element in case the condition evaluates to false. The mechanics they use to hide the view, though, are different.

ng-show (and its sibling ng-hide) toggle the appearance of the element by adding the CSS display: none style.

ng-if, on the other hand, actually removes the element from the DOM when the condition is false and only adds the element back once the condition turns true.

Since ng-show leaves the elements alive in the DOM, it means that all of their watch expressions and performance cost are still there even though the user doesn’t see the view at all. In cases where you have a few big views that are toggled with ng-show you might be noticing that things are a bit laggy (like clicking on buttons or typing inside input fields).

If you just replace that ng-show with an ng-if you might witness considerable improvements in the responsiveness of your app because those extra watches are no longer happening.

That’s it: replace ng-show and ng-hide with ng-if!

Caveats and Pitfalls of ng-if

  • Measure, measure, measure: As with every optimization, you should not apply this without measuring and validating that it does speed up your app. It can, potentially, actually make things slower, as I explain below.
  • Your controllers will be rerun: The controllers and directives in the element that’s being removed and added again will actually be recreated and so their initialization logic will run again. This is in contrast to ng-show where things are always there in memory, and so are only initialized once. You need to make sure your code handles being rerun properly.
  • Sometimes initialization is more expensive than keeping things around: That’s to say that in some cases the cost of removing the element from the DOM and then recreating it to add again can be a heavy operation all by itself. In those cases you might feel that it takes too long for the element to reappear. In those cases this trick might actually degrade your app’s performance, so remember to check and measure!

That’s it. Enjoy making your app a bit snappier. If you care about performance in Angular you really should read about speeding ng-repeat with the track by syntax.

Controllers Should Not Be Control Freaks

| Comments

It’s super easy to get baffled about what should you put inside your controllers. Especially if your background is with frameworks touting MVC, you might think that the name “controller” in Angular indicates some kind of control.

The idiom in Angular is to keep your controllers extremely thin. That is the common paradigm, and also the general direction things are going as you can see in this great and common style guide, the introduction of “controller as” syntax and with Angular 2’s upcoming removal of controllers.

Let’s try to make sense of the controllers’ valid responsibilities.

Why keep controllers thin?

First and foremost, writing your code this way results in more maintainable code. When you don’t watch out, controllers tend to become tangled beasts that take on too much responsibility. This makes it extremely hard to test them properly, reuse stuff and is just bad programming as agreed by everyone who’s heared of the Single Responsibility Principle.

Also, I already mentioned that Angular 2.0 is dumping controllers. No, you should not start working in 2.0 now or worry about it too much, but it does make sense to be aware of where things are headed and to start accepting the lessons the Angular community has learned and accepted.

What should not be in controllers?

Getting technical, let’s start with all the things that you should probably not put in your controllers.

  • HTTP stuff: Probably the easiest way to get scolded on an Angular forum these days is to share code that’s performing $http calls directly from your controllers. It has become common practice to hide this inside services as well, even if some Angular documentation has examples doing otherwise. Having a specific service for handling the requests of a certain aspect (e.g. a REST resource) means that you can easily find everyone that’s using it and can make changes in a single place in case the server’s representation of the object changes. Software engineering, who would’ve thought.
  • DOM manipulation: There’s a reason that controllers don’t have access to their element easily. That’s because DOM access is reserved to directives in Angular. You probably know this already, but still.
  • Complex view logic: While controllers are bound to views and end up managing them, if you notice that your logic is become complex you should consider pushing it outside to a specific directive or maybe put some of the logic in a specific service.
  • Model logic: Most controllers are responsible for manipulating/displaying a specific model and tend to take on the responsibility for managing that model. You should take that logic outside of the controller, preferably into a Model object that is a good old object. Yes, even though Angular doesn’t have an angular.model() function it doesn’t mean you can’t still have them. Just create plain JavaScript classes or even use a service to declare the class of your models.
  • Business logic: Business logic is important, changes a lot, and usually will be reused across multiple controllers as your app grows. Because of this it makes a lot of sense to create specific services for the different aspects of your business logic and use them from your controllers. This makes the logic easily testable and reusable.

What should be in controllers?

Controllers with Angular-zen spirit should essentially map actions from the view to the different models and services, with as little logic as possible. Most of your controllers should be basic delegation once they’ve set up the view model on initialization.

In a way, good controllers let go of control!

An example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
angular.module('tasks').controller('TasksCtrl', function($scope, $http) {
    var vm = this;

    function activate() {
        // Bad controller! Don't access $http!
        $http.get('/tasks').then(function(response) {
            $scope.tasks = response.data;
        });

        // Much better - use a service:
        TasksStore.getAll().then(function(tasks) {
            vm.tasks = tasks;
        });
    }

    activate();

    $scope.showDueSoonTasks = function() {
        // Bad controller! This is business logic!
        $scope.tasks = _.filter($scope.tasks, taskDueDateIsIn(2, 'DAYS'));

        // Much better - put the business logic somewhere else
        vm.tasks = TasksPrioritizer.getDueSoon(vm.tasks);
    };

    $scope.snoozeTask = function(task) {
        // Bad controller! Stop reaching into your models!
        if (task.dueDate < now()) {
            task.dueDate = addDate(task.dueDate, 2, 'DAYS');
        }

        // Better - use real models with responsibility:
        task.snooze();
    };
});

Keep (cont)rolling!

Resourceful Angular: $http, $resource and Restangular head to head

| Comments

Probably the most common task you do in your Angular app is making REST requests. You’d think something like this, which is at the core of any SPA, would have a consensus in the community about the Right Way™ to do it.

But actually if you’ve looked around you probably came across multiple camps: those who use $http, those who use $resource and those who use bigger guns like Restangular (there are others, but in this post I’ll focus on it as the most popular one by far).

You probably wondered what are the differences and which should you use. This is a quick summary trying to make sense of those options.

Overview

$http

This is the easy and straightforward route. $http is pretty much what you’d expect it to be and since it’s so raw it means that you’ll probably write more code than you will with the alternatives but have the most flexibility and control. There’s no limitation on what you can do.

It’s also built in with Angular and doesn’t require adding another dependency.

$resource

$resource (also known as ngResource) is Angular’s attempt at supplying a higher level of abstraction over $http. It used to be built in and has been separated to an external dependency. It basically supplies you with a relatively easy way to create objects that perform the different CRUD requests transparently.

I think this example pretty much shows the use case they had in mind, in which we define the User model and show how to update one:

1
2
3
4
5
var User = $resource('/user/:userId', {userId:'@id'});
User.get({userId:123}, function(user) {
  user.abc = true;
  user.$save();
});

$resource’s history has been wonky, as it had a lot of limitations and bugs in earlier versions of Angular and still has documentation and API that are a bit cryptic to master. Usually, if your object model is complicated enough to warrant wrapping $http I’d jump straight to Restangular.

Restangular

Restangular has several differences from $resource, but 2 main ones are that it has a saner API and embraces objects and nested models whole heartedly.

If you have an object model that’s complicated Restangular can be a big help and save you writing a lot of boiler plate code. It also has pretty much every feature you can dream up and great documentation.

Which should you use?

First, I’ll say that IMHO (which seems to be shared by many) $resource isn’t a real player here. You’d either use $http or Restangular.

Now, if you really prefer keeping boiler plate code to a minimum or like the extra abstraction Restangular is quite nice.

I, though, usually prefer reducing dependencies to a minimum and like to have ultimate control. There are a few little issues with Restangular that together boil up to make me rather just go with $http most of the time:

  • It’s an extra dependency. That means more time to load my app, more stuff to learn and more stuff to manage.
  • I don’t like the idea of having “special objects” floating around. It means that if you have services that handle models they can’t necessarily treat all objects the same – if the object was fetched over the network it’s “restangularized” and has extra stuff, if you just created it in the client and haven’t saved it yet it behaves a bit differently.
  • It makes it harder to spot where a certain endpoint is being used. If you use $http to create a service responsible for operating on a specific model you can easily find all the calls for a specific endpoint easily. For example, say your app has Projects, which have users, and Tasks, which have users. If at some point we want to rename task’s “users” to “assignees” you’ll have a hard time going over every getList('users') in the code to see if it’s a project or a task. With services I’d probably just change the TasksStore.getUsers() function.
  • Restangular’s nested objects that return more and more objects make testing cumbersome. It’s harder to mock out a certain dependency since you end up having to create mocks that return more mocks. This is a matter of taste, but I usually look at this as a code smell (a-la the Gary Bernhardt school of thought).

So, yes, I prefer $http, but for some people Restangular “clicks”, and that’s awesome. Just stay away from $resource.

Happy ajaxing!

My Angular Debugging Tips

| Comments

Yeah, I know, your code is awesome and you never write any bugs. My code does have bugs every now and then. In those cases these tips come in handy.

ng-Inspect Element

Perhaps the most useful trick is to know that once you right click on an element on screen and pick ‘inspect element’ Angular makes it very easy for you to get things going.

In the browser’s developer tools console write angular.element($0) and you now have access to all the good things:

  • Scope: angular.element($0).scope() will return the scope for the element. This is golden.
  • Controller: angular.element($0).controller() will give you the controller, doh.
  • Injector: angular.element($0).injector() returns the app’s injector, which you can then use to get access to other things (e.g. injector.get('MyService') or injector.get('$http'))

Extensions

There’s a growing number of handy extensions and snippets for Angular. Here are a few ones to try out:

  • Batarang – An official extension from Angular itself that most people love just because it shortens the previous trick from angular.element($0).scope() to $scope and the likes.
  • ng-inspector – Has similar tools to Batarang’s for looking at your app’s hierarchy, walking the scopes, etc. but works on Safari and Firefox and not just Chrome.
  • ng-stats – A little utility to show your app’s digest/watches situation, handy for spotting performance issues.

Print debugging

Print debugging is always useful, but sometimes console.logs alone are not enough. For these cases Angular provides us with a very nice little filter that even the docs say is just for debugging – the json filter.

Have some model or scope you want to see easily? Just print it: <pre>{{ someModel | json }}</pre> (Using pre means you’ll see the json properly formatted).

Bugs be gone

I hope this will help you out. If you have any other tricks I’d love to hear!

Happy debugging (well, you know, as much as possible).

Should You Use Angular 2.0 or 1.x?

| Comments

This question might seem trivial, but I keep seeing it pop up again and again everywhere in the Angular community. With all respect to the maintainers, they’ve managed to confuse quite a lot of smart people with this.

If you’re new to this world and want to get started with a new project you might have wondered whether you should use 1.x or “jump straight” to Angular 2. On the other hand, if you’ve already got Angular experience you’re probably getting worried about the impending changes and wondered whether you should start adapting to it.

And those are valid questions. After all, what are you supposed to think when every newsletter and forum are filled with articles about Angular 2’s forms, architecture, new router, Typescript, etc.? Why would the community push out so many articles about writing simple apps in Angular 2 if it shouldn’t be used?

The executive summary: There’s no Angular 2 to use, so Angular 1 is still the way to go.

A bit more details

Angular 2 is getting a lot of hype and attention, but the reality is that it is still in alpha and changes quite rapidly. It is not intended at all to be used in production yet. So, really, you can’t and shouldn’t start your company’s next big project using it.

So what’s up with all the articles? It’s a combination of a lot of things.

First, people are excited because Angular 2 brings a lot of nice stuff, and so they start exploring it and writing about the benefits.

Furthermore, it is impossible to be in this community and not hear people mumble about the Angular 2 migration that “will break all our code”. This motivates a lot of people to start learning 2.0 to see what is awaiting us and start understanding what’s going on.

Also, because it’s still heavily under development, writing about its current state and complaining about things actually might change things for the better as opposed to the general useless complaining we’re used to on the internet. It is a rare opportunity to affect technology you might be using for years to come.

All this is just to say that while Angular 2 is getting a lot of hype (and probably will get even more before it’ll be out), it is not production ready. If you have the time or freedom and find it interesting, of course you should give it a try, and even if you don’t have time it’s probably a good idea to keep up with the news and reading material. Eventually, the migration path will start getting clearer and when it does you’ll probably want to know as early as possible what you should be changing.

How will you know when to it’s time to start seriously looking at Angular 2?

If you’re reading this post, I’m assuming you read the news every once in a while. So just make sure to keep doing it. There are plenty of communities and newsletters (cough like the one here on my blog cough) you can trust to update you.

Happy Angularing!

Simple pagination and URL params with ui-router

| Comments

ui-router rocks. There’s a reason it’s become the de facto router in Angular. Its power is in its versatility, but it takes time to master all the different knobs it has to offer.

This shortie post is about something we face quite often: adding simple query parameters to our SPA for stuff like pagination and sorting.

Problem definition

The use-case is straightforward: say you have a long list of information that you’d like to present with pages and different sorting options.

The ideal case would be that our controller, let’s call it ListCtrl, has 2 optional parameters – page and sort– with default values (obviously 0 for pages and we’ll use upvotes for sorting).

Basically we’d like to have the following URLs be associated with the following parameters passed to ListCtrl:

  • /list with {page: 0, sort: 'upvotes'}
  • /list?page=1 with {page: 1, sort: 'upvotes'}
  • /list?page=2&sort=date with {page: 2, sort: 'date'}

This is really easy as pie:

State configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$stateProvider.state('list', {
    url: '/list?page&sort',
    controller: 'ListCtrl',
    controllerAs: 'list',
    templateUrl: 'list.html',
    params: {
        page: {
            value: '0',
            squash: true
        },
        sort: {
            value: 'upvotes',
            squash: true
        }
    }
});

You can see this looks like an ordinary state with a few details: we specify the names of our parameters in the url and provide those parameters’ default values and set them to squash, which means ui-router won’t put them in the URL if their current value is the default value (read all about this configuration in the docs of $stateProvider.

That’s about it!

Simple Controller

Our controller might look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function ListCtrl($stateParams, $state) {
    var self = this;
    self.page = parseInt($stateParams.page, 10);
    self.sort = $stateParams.sort;

    function sortList() {}
    function updatePage() {}

    sortList();
    updatePage();

    self.nextPage = function() {
        $state.go('.', {page: self.page + 1});
    };
    self.prevPage = function() {
        if (self.page > 0) {
            $state.go('.', {page: self.page - 1});
        }
    };
    self.sortChanged = function() {
        $state.go('.', {sort: self.sort});
    };
}

Note that ui-router’s parameters’ default values must be strings and are passed to us from $stateParams as strings, so we take care to use parseInt.

You can see that updating the URL parameters is quite straightforward – you just call $state.go with the current state ('.') and the parameters you want to update – the rest remain as-is!

Updating parameters with reloading the controller

The example above worked because $state.go() would reload our controller with updated $stateParams. While this might be all you need sometimes, other times you won’t want to reload the whole controller.

In those situations you can use $state.go() with the special {notify: false} configuration which effectively prevents your controller from being reloaded (see the documentation for full details). What it does mean, though, is that we’ll need to update sorting/paging ourselves in the controller:

1
2
3
4
5
self.nextPage = function() {
    self.page++;
    updatePage();
    $state.go('.', {page: self.page}, {notify: false});
};

That’s about it! You can download a really simple skeleton that shows how this works here.

Happy routing!

Using ng-change instead of $watch in Angular

| Comments

In the olden days, before you used MVC frameworks such as Angular, you were probably used to doing stuff like this in jQuery:

1
2
3
4
5
function showNameChanged() {
    // stuff...
}

$('input.show-name').change(showNameChanged);

This achieves the simple task of performing an operation whenever the user typed something inside an input, using JS change events.

In Angular, though, most people would consider this code the equivalent:

1
<input type=text ng-model=show.name>
1
$scope.$watch('show.name', showNameChanged);

Now, you might think I’m being nit picky here, but I’d usually rather write it like this:

1
<input type=text ng-model=show.name ng-change="showNameChanged()">

ng-change?

I’m always surprised that this directive is foreign for a lot of newcomers to Angular, and that $watch seems to be the tool everyone reach for first. ng-change is a simple directive that operates much like using jQuery to register a change event listener.

In my opinion, this is the “real” equivalent of the first code sample we saw.

The differences

  • Using ng-change would call our showNameChanged() function only on actual changes to the input by the user. Watches, as you might know, are called in other cases too: right when they’re being defined the first time and on changes made to the value not by the user, e.g. programmatically.
  • I’m a big believer in expressing intent when writing code (you do know The 4 Rules of Simple Design, right?). If my intent is to only listen to changes by the user, and I don’t expect the input to be changed programmatically, I would rather explicitly show that. Using $watch means whenever you read this code in the future you’ll have to consider whether it’s being triggered by something else, too.
  • Another plus for intent for ng-change is that you can see from the template that this input is bound to something and how. Otherwise you’d need to start looking for the value in ng-model in the controller for usages. This way you can see right away who’s listening for these changes.
  • Less code. And less code == less things to debug. As you can see above we didn’t need to add another line to the controller to listen for input changes.
  • Using ng-change is a tiny bit more performant, since it uses one less watch expression. Since Angular knows it should only call the expression on change events it doesn’t need to keep evaluating it on every digest cycle, as opposed to, well, a watch. Yes, just this one doesn’t matter a lot, but across a big app these things stack up.

Of course, sometimes $watch is what you want. But sometimes – it ain’t!

Happy coding!

AngularJS: Pitfalls using ui-router’s resolve

| Comments

If you’ve been doing Angular any amount of time, I hope you’ve found and started using the great ui-router library. It truly helps when building anything that’s larger than a simple project.

A really useful feature is resolves. It is ui-router’s way of letting us provide values to the different controllers it manages, in a way that makes them simpler – it hides asynchronous operations and so controllers are more linear.

For example, a controller that needs a specific goat might be written like so with vanilla Angular:

1
2
3
4
5
6
angular.module('app').controller('GoatCtrl', function(GoatService) {
    var self = this;
    GoatService.getGoat().then(function(goat) {
        self.goat = goat;
    });
});

But if this is a controller of a route defined by ui-router, we can use a resolve to hide the promise from it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
angular.module('app').config(function($stateProvider) {
    $stateProvider.state('goat', {
        url: '/goat',
        controller: 'GoatCtrl as goatCtrl',
        templateUrl: 'goat.html',
        resolve: {
            goat: function(GoatService) {
                return GoatService.getGoat();
            }
        }
    });
});

angular.module('app').controller('GoatCtrl', function(goat) {
    this.goat = goat;
});

The benefits, I assume, are clear: cleaner controllers, especially if you have multiple things that need fetching and less meddling with asynchronous code and promises.

But, as always, there are pitfalls and use cases where this solution comes short that you should be aware of in order to make the right decision.

The pitfalls

Might feel slow/laggy/stuck

You’ve had this happen to you many times (probably earlier today): you press a button which triggers a route change. If that route has a resolve that takes a few seconds to complete, you won’t get any feedback about anything happening until the resolves are resolved. This can be frustrating, making you wonder did I click it? Perhaps you’ll click again just to make sure.

In a resolve-less state, the new controller and template would start rendering immediately, which by itself provides some feeling of progress. I usually go for not using resolves in this case and have the controller show a proper loading state for itself. This way it doesn’t matter where you’re transitioning to this route from, you’ll still have the proper loading indication.

You can also, of course, have the button show some spinner or something until the route transition happens.

Errors happen in no-man’s-land

You have a resolve that makes an AJAX $http call. Eventually it will fail. Where will you handle the error? You don’t have a controller yet to manage things at this point.

Make sure to either have some generic error handling or make your resolves always return some value, even on errors, and then handle those situations in your controller.

It adds complexity to the code

Even though the solution makes some parts of the code clearer, like the example at the top of this post, it has a price. The dependencies of the controller are now pushed away to a place far far away. Some of the setup of the controller now happens in a different place, even though it is still very coupled – each resolve maps to an argument for the controller.

I don’t always like the effect this has on my code and if I notice that I have to keep flipping back and forth between the controller and the state setup I might decide to just push it all together (maybe using a helper service) to make things clearer and have them just sit together.

Take aways

Resolves can be very handy and I definitely use them, but it’s important to understand where they might clash with maintainability and UX and make sure to keep tabs on it.

Happy routing!

Don’t use $http’s .success()

| Comments

An example of performing AJAX requests in Angular is probably the second thing you ever saw when getting into Angular (right after an example showing off two way binding). It does look very sexy and easy when you look at it, since most examples look something like this:

1
2
3
$http.post('/products', product).success(function(createdProduct) {
    // w00t!
});

This is usually the first time you learn about promises in Angular and how they work. Later when you get more in depth you’ll realize that only $http’s promises have success() and error() functions, while regular promises just have then().

You might wonder what’s the difference, really. Well, Angular is all about decisions, and this time I want to stress how using success() is a bad one.

How success() is implemented

If we look in Angular’s source code here we can see that success is basically:

1
2
3
4
5
6
7
promise.success = function(fn) {
    // ...
    promise.then(function(response) {
        fn(response.data, response.status, response.headers, config);
    });
    return promise;
};

So it’s just like then() but deconstructing the response object. This is essentially just syntax sugar so you’d have a callback that gets the JSON object back as its first argument and save you reaching into response.data yourself.

The problem

First, I hate anything that creates inconsistency in my code. If we use success() we’ll still have to use then() in every other place that has a promise, which makes this syntax sugar more of a cognitive leak in my opinion than anything useful.

Second, it couples your code in a subtle way – you’re telling everyone you’re actually reaching to the network to get something.

Say we have a service for managing some resource:

1
2
3
4
5
6
7
angular.module('app').factory('ProductsService', function($http) {
    return {
        getProduct: function(id) {
            return $http.get('/products');
        };
    };
});

And this is used later like so:

1
2
ProductsService.getProduct(123).success(function(product) {
});

This means that all users of ProductsService definitely know that getProduct() goes out to the web to get data. What if you later add caching? What if you decorate ProductsService with some wrapper and need to chain the promise it returns? If everyone assume your promises have .success() it’s going to be a PITA.

What I like to do instead

On several projects with multiple teams we’ve found this idiom to be quite nice:

1
2
3
4
5
6
7
8
9
angular.module('app').factory('ProductsService', function($http) {
    return {
        getProduct: function(id) {
            return $http.get('/products').then(function(response) {
                return response.data;
            });
        };
    };
});

This way, we’re using promise chaining to hide the $http promise and hide response data except for the JSON itself (e.g. response headers, request config). This means that we later can easily swap the original promises with cached promises, or generate random data with a fake promise when testing. Suddenly no one cares about HTTP.

I’ve found that 99% of the time your callers don’t need/know how to handle HTTP errors anyway, so hiding it works. I prefer to go with generic error handlers where needed.

AngularJS: Dynamically loading directives

| Comments

It’s hard to write a webapp today without some sort of dynamic feed/list: Facebook’s news feed has photos, text statuses, ads, Twitter’s feed has promoted tweets, image tweets, retweets, and maybe you have a chat/messaging feed in your app with text, videos, photos and stickers.

While this is relatively common, it might not be straightforward to do so in Angular, or what is the Right Way™ for doing this.

The problem

Say that we get from a REST API a list of feed items, that look somewhat like this:

1
2
3
4
5
6
7
8
9
10
[
    {
        "type": "text",
        "body": "hello"
    },
    {
        "type": "image",
        "url": "http://..."
    }
]

Naively, we might say what we really want is to create 2 directives, one for rendering text items (text-feed-item) and one for images (image-feed-item), and write something that looks like this:

1
<div {{item.type}}-feed-item item=“item”></div>

Of course, this isn’t valid Angular code. So what should you do?

Keep it simple, stupid!

One of my main rules of thumb is to keep away from complexity as much as I can and be explicit. This means that if I have only a handful of different item directives to choose from, I’ll write something very explicit, like this:

1
2
3
4
<div ng-switch=“item.type”>
    <div ng-switch-when="text" text-feed-item item="item"></div>
    <div ng-switch-when="image" image-feed-item item="item"></div>
</div>

This has the several advantages:

  • Simple as can be
  • Explicit
  • Easily searchable (say, if you want to find who uses the image-feed-item directive you can use plain search and find this)

But, in case you have more than a handful of different feed item types this might get out of hand or just plain get annoying.

$compile

Angular’s way of dynamically adding directives to the DOM is compiling them. I know the word “compile” feels quite odd in our little corner of web development, but for some reason that’s the word they chose for the process of having Angular parse a DOM node and executing all the Angular goodness it requires.

Making a dynamic directive that does basically what our first naive attempt looked like isn’t that hard, once you know about Angular’s $compile service:

1
<div item-generator item="item"></div>
1
2
3
4
5
6
7
8
9
10
11
12
angular.module('myApp').directive('itemGenerator', function($compile) {
    return {
        scope: {
            item: '='
        },
        link: function(scope, element) {
            var generatedTemplate = '<div ' + scope.item.type
                + '-feed-item item="item"></div>';
            element.append($compile(generatedTemplate)(scope));
        }
    };
});

This will result in something that looks like this if you inspect the DOM:

1
2
3
4
5
<div item-generator item="item">
    <div image-feed-item item=“item”>
        <img ...>
    </div>
</div>

As you can see, $compile has two steps. First, we call it with the HTML we want to generate, which returns a function. We then call that function with the specific scope we want the generated element to have and then we actually get the new element that we can add to the DOM.

Yes, this is more complicated, requires being more comfortable with how Angular works and doesn’t have the benefits I listed above for the simpler solution, but sometimes this approach is necessary.