codelord.net

Code, Angular, iOS and more by Aviv Ben-Yosef

Understanding Optional AngularJS Bindings

| Comments

It seems that few developers are familiar with the ability to mark bindings in AngularJS as optional, and what that even means. After all, you may have seen that even when you don’t pass a binding to a directive/component, things seem to work, so why bother?

In this post we’ll go over the different binding types and understand what, exactly, setting them as optional means, so you’ll know when to use it and what might happen if you don’t.

Two-way = bindings

Two-way bindings, when not specified as being optional, would only complain when the component tries to assign to them. That is because, by definition, Angular would attempt to update the parent component as well. If the parent never gave a value, Angular will not be able to update it, and so would throw a runtime exception.

For example, consider a component called userEditor that defines its bindings like this:

1
2
3
bindings: {
  user: '='
}

If you were to instantiate the component without the user bindings, e.g. <user-editor></user-editor>, at first nothing bad would happen. The component’s controller, when accessing the this.user property, will see that its value is undefined.

But, if the component would ever attempt a reassignment, such as this.user = {}, it would result in an error.

In those situations, in case the binding is not mandatory, you should specify it as being optional:

1
2
3
bindings: {
  user: '=?'
}

Then, reassigning would just silently work, without actually updating anything in the parent.

Though, I will stress that reassignments should be rare and you should probably be using one-way bindings, described below.

One-way < bindings

Since one-way bindings are, hmm, one-way, they don’t have the same problem as described above on reassignments. Angular just doesn’t care that the component is reassigning, and so, for these bindings, the behavior would be the same with or without the optional setting. If the user of the component does not pass a value for the binding, it would be undefined in the component’s controller and that’s it.

Yet it can be specified as being optional, by providing the value <? in the bindings definition (or scope if you’re using a directive).

Expression (function) & bindings

The & binding is mostly used in order to pass a callback to a component–a simple function that can be invoked by the component’s controller.

By default, when these bindings aren’t set up with an initial value by the parent component, they simply translate to a function that does nothing and returns undefined (also known as angular.noop). This makes it completely safe for the child component to call that binding without risking a crash, as a nice example of the Null Object pattern.

And yet, sometimes the component would need to know whether the callback was passed at all or not, e.g. to decide whether certain work needs to be done.

In those scenarios it is possible to specify the binding as being optional, with &?, and then it is passed to the controller as undefined, instead of angular.noop. Then the controller can check for it, e.g. if (this.callback), and take action according to the value.

This does mean, though, that the controller can no longer blindly invoke the binding; it has to check first that it is defined.

Bottom Line: Use Optional If You Mean It

As you might understand, one can do Angular for quite a while without ever having to use optional bindings. And yet, I would argue that they should always be used if, indeed, the bindings are optional.

Also since in two-way bindings it would be a bug waiting to happen to do otherwise. Yet mainly because I believe that doing so helps to write better, more maintainable code, that is later easier for future users of the component to reason about and understand (be those users other developers or future-you).

By adopting a convention across your codebase to always specify optional bindings when necessary, your team will have another aid for explicitly documenting your code.

Just remember to add that ? to the binding definition!


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

Converting Angular Controllers to ES6 Classes

| Comments

After covering the process of transforming Angular services to ES6 classes, and digging into how injection works with ES6 classes, it’s time to take a closer look at controllers.

Controllers, being the basic building block in Angular, is also where you’ll get your biggest bang-for-the-buck for making the ES6 transition, in my opinion. That is, assuming your project is already making use of controller-as syntax, as opposed to exposing all of your controllers’ logic directly on the $scope object.

Let us look at an example controller:

1
2
3
4
5
6
7
8
9
10
11
12
function UsersCtrl(UsersStore) {
  var self = this;
  self.$onInit = function() {
    UsersStore.get().then(function(users) {
      self.users = users;
    }):
  };

  self.updateUser = function(user) {
    UsersStore.updateUser(user);
  };
}

(Note how all initialization is taking place inside the $onInit hook, which is a must starting from 1.6+)

Here is how the above controller would be written as a class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class UsersCtrl {
  constructor(UsersStore) {
    this.UsersStore = UsersStore;
  }

  $onInit() {
    this.UsersStore.get().then(users => {
      this.users = users;
    });
  }

  updateUser(user) {
    this.UsersStore.updateUser(user);
  }
}

The conversion steps are:

  1. Change the function to be a class definition
  2. Create inside it a constructor and move all injections to be its parameters. Inside this constructor assign every injected service to be a member of the new class.
  3. Change every method declared previously as this.function to be declared as a regular method in a class.
  4. Update all references to injected services to use the local properties, e.g. this.UsersStore instead of UsersStore.

Keep in mind that while classes have a constructor, you should not be using them for any real logic. You want to keep them as stupid as possible, only making sure to save injections. All other logic should be kept inside the $onInit hook.

Also note that ES6 classes do not have a concept of private methods/members. In the function syntax you could have declared a var innerData inside the UsersCtrl function, and innerData would not have been accessible to the template. That’s not the case with classes, and so I usually opt for a naming convention where templates are not allowed to access any methods or members on the controller that start with a _, e.g. _innerData.

You might find it icky, but that’s just the way it is. TypeScript, which you might also be considering, supports private members and even saves you the constructor boilerplate.


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

Angular Dependency Injection Annotations With ES6 Classes

| Comments

After covering how ES6 classes can be used for defining services in Angular in the previous post, I was asked how do these play along with Angular’s dependency injection annotations.

To recap, dependency injection annotations are used so that Angular would know what it should be injecting even when code is obfuscated/minified. This is a regular service with injection in ES5:

1
2
3
angular.module('app').service('Service', function($http) {
  this.get = function() { ... };
});

And that example with explicit annotations would look like so:

1
2
3
angular.module('app').service('Service', ['$http', function($http) {
  this.get = function() { ... };
}]);

How does this play along with ES6 classes?

The above example as a class looks like this:

1
2
3
4
5
6
7
8
angular.module('app').service('Service', Service);

class Service {
  constructor($http) {
    this.$http = $http;
  }
  get() { ... }
}

And in order to add proper annotations to it, simply add this line at the bottom:

1
Service.$inject = ['$http'];

That’s all there’s to it, if you insist on adding these manually.

But please, stop doing it like an animal, and incorporate something like ng-annotate. Given that you’re using ES6, you very likely already transpiling your code into ES5, and ng-annotate can simply go over your code at that point and add these as necessary.

Keep it classy! </dadpun>


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

Moving Angular Factories to Services With Classes

| Comments

When I first wrote about the differences between services and factories in Angular, the bottom line was that the difference is semantic and so you should just pick one and stick with it.

Back then I made the point that, personally, I find factories require less boilerplate code and so they are often my choice.

Since then, a use case for using services has become more common, and that’s when using ES6/ES2015 classes.

When making use of classes, services are the right choice.

That’s because classes map naturally to an Angular service, let’s see how.

Take a look at this non-ES6 UsersStore:

1
2
3
4
5
6
angular.module('app').factory('UsersStore', function($http) {
  return {
    getAll: function() { ... },
    get: function(id) { ... }
  };
});

Converting this to an ES6 class would look like this:

1
2
3
4
5
6
7
8
class UsersStore {
  constructor($http) {
    this.$http = $http;
  }

  getAll() { ... }
  get(id) { ... }
}

The registration line would then be changed to this:

1
angular.module(app).service(UsersStore, UsersStore)

The behavior for all existing code that injects UsersStore will remain the same, this is a seamless transition.

An important note, though, is the way injection is now performed. Note that $http is now provided to the class’s constructor. In order to be able to access the injected service later, for example in the getAll method, we have to save it as a member. Then, the code in the converted getAll function should make sure to reference it as this.$http.

The extra typing around a constructor might put off some people, but looking at the bright side I find it helps making it more painful to write uber controllers and services that take on too much responsibility :)

Subscribe below to learn more about modern Angular and using Angular with ES6.


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

Screencast: Debugging Bad Performance in an AngularJS App

| Comments

This is a video walkthrough of the debugging process of a slow AngularJS app, until pinpointing the exact deep $watch that is causing the performance bottleneck. See how tools such as ng-stats, profiling in the Chrome Dev Tools and editing Angular’s code come together to solve this issue!


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

The Performance Difference Between ng-bind and {{}}

| Comments

Interpolation is one of the first things newcomers to Angular learn. You can’t get around writing your first Angular “Hello, World” without some sort of simple interpolation like Hello, {{ $ctrl.name }}.

But, you may have come across the ng-bind directive, seen it used and realized it’s pretty much the same as straightforward interpolation. The above example using ng-bind would look like this:

1
Hello, <span ng-bind="$ctrl.name"></span>

Why do we have both {{}} and ng-bind?
Is there any reason to use one over the other?
In this post we’ll see exactly what are the differences and why ng-bind is preferable.

The original reason: Flash Of Unstyled Content

FOUC is a term that’s been around for quite some time. In Angular, it mostly refers to when a user might see a flash of a “raw” template, before Angular actually got to compiling it and handling it correctly. This happens from time to time when using {{ }} interpolation, since Angular has to go over the DOM, find these and actually evaluate the proper value to put in them.

It looks unprofessional and also might make non-technical people think there’s something wrong with the page.

ng-bind, on the other hand, makes this a non-issue. Since the directive operates as an element attribute, and not as the element’s text value, there’s nothing visible to the user before Angular finishes compiling the DOM.

This can also be circumvented using plain {{ }} by using tricks like ng-cloak, but I always found those to be a hassle.

The real reason: Performance

While it might seem like there’s no real reason to have a different performance impact if you’re writing {{ $ctrl.hello }} or <span ng-bind="$ctrl.hello "></span>, there is.

If you’ve been following my posts for a while, this shouldn’t be the first time you hear of a case where 2 things that seem like they should be pretty identical are actually very different when it comes to their run-time performance.

The thing is that when it needs to keep track of interpolated values, Angular will continuously re-evaluate the expression on each and every turn of the digest cycle, and re-render the displayed string, even if it has not changed.

This is opposed to ng-bind, where Angular places a regular watcher, and will render only when a value change has happened. This can have a major impact on the performance of an app, since there is a significant difference in the time each way adds to the digest cycle.

In my benchmarks, I’ve seen it go as far as being twice as fast to use ng-bind. You can see for yourself in these samples: with interpolation vs using ng-bind (and since these are basic interpolations, I wouldn’t be surprised the problem is worse for complicated expressions).

I’m not big for premature optimizations, but I do prefer sticking to a single way of doing things across a project. That is why I usually opt for sticking with ng-bind from the start.

Happy hacking!


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

Techniques for Improving ng-repeat Performance

| Comments

ng-repeat is notorious for often being the biggest performance bottleneck in Angular apps. It is common practice, when performance tuning lists, to use track by or one-time bindings. Surprisingly, trying to combine both of these practices usually has unexpected results. In this post, we’ll go over the different scenarios ng-repeat is usually used for, and the possible improvements for speeding it up ng-repeat.

Note that before diving into any optimizations, I highly suggest measuring and tracking down the problematic parts of your app.

Refreshing the whole list

Scenario

The list you’re rendering with ng-repeat isn’t edited/changed on a per-line basis, but simply reloaded, e.g. with a “Refresh” button that fetches the model again from the server and replaces the currently displayed list.

The act of re-rendering the whole list feels laggy. Usually this means there’s some jank, or the browser seems to freeze for a bit before actually rendering.

Improvement: track by

Use track by as detailed here. In the above scenario, when the list is changed Angular will destroy all DOM elements in the ng-repeat and create new ones, even if most of the list elements remained identical to their previous versions. This, especially when the list is big, is an expensive operation, which causes the lag.

track by lets Angular know how it is allowed to reuse DOM elements in ng-repeat even if the actual object instances have been changed. Saving DOM operations can significantly reduce lag.

A completely static list

Scenario

Your component displays a list of items that’s never changed as long as the component is alive. It might get changed when the user goes back and forth between routes, but once the data has been rendered and until the user moves on to a different place in your app, the data remains the same.

This is common in analytics apps that display results of queries and don’t actually manipulate the data afterwards.

While the list is on the screen the app might feel sluggish when interacting with it, e.g. clicking on buttons, opening dropdown, etc. This is usually caused by the ng-repeat elements introducing a lot of watchers to the app, which Angular then has to keep track of in every digest cycle.

I’ve seen my fare share of apps with simple-looking tables that made an app grind to a halt because under the hood they had thousands of watchers, heavy use of filters, etc.

Improvement: one-time bindings

Just for the case where the data should be rendered for a single time we were given the one-time binding syntax.

See the full explanation here, but basically by sprinkling some :: inside the ng-repeat elements’ bindings, a static list can have the number of watchers reduces to even nothing.

This means that once the rendering has finished the table has no performance impact on the page itself.

Editable content

Scenario

Your app displays a list or a table that can be changed by the user. Maybe some fields can be edited. Or perhaps there’s a table cell with a dynamic widget.

The list is big enough to have the same performance problems discussed in the previous part, but, since it needs to pick up on changes in the data, simply using one-time bindings breaks its usability. The list stops displaying changes, since all our watches are gone.

Improvement: immutable objects and one-time bindings

When you mutate one of the objects inside a list, Angular doesn’t recreate the DOM element for it. And since the DOM doesn’t get recreated, any one-time bindings will never be updated.

This is a great opportunity to start moving into the more modern one-way data flow and use immutable objects.

Instead of mutating the objects, e.g.:

1
2
3
function markTodoAsDone(todo) {
  todo.done = true;
}

… treat your models as immutable. When a change is needed, create a clone of the data and replace the model object inside the list:

1
2
3
4
5
function markTodoAsDone(todo) {
  var newTodo = angular.copy(todo);
  newTodo.done = true;
  todosListModel.replace(todo, newTodo);
}

Why does this work? Consider this template:

1
2
3
4
5
<div ng-repeat="todo in $ctrl.todosListModel.get()">
  <div ng-bind="::todo.title"></div>
  <div ng-if="::todo.done">Done!</div>
  <button ng-click="$ctrl.markTodoAsDone(todo)">Done</button>
</div>

Since all the bindings inside the ng-repeat template are one-time bindings, the only watcher here is the $watchCollection used by ng-repeat to keep track of $ctrl.todosListModel.get().

Had we simply mutated the todo object, the $watchCollection would not get triggered and nothing would get rendered. But since we’re putting a new object inside the list, $watchCollection will trigger a removal of the old todo, and an addition for the new one. The addition will create a new DOM element for our todo, and so it will get rendered according to its latest state.

Summary

ng-repeat can be tamed, at least partially, if you take care to use it according to your specific use case.

I hope this helps you speed your app a bit!


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

Testing Components with $onChanges Using angular-stub-changes

| Comments

My previous post showed how to set up a component’s controller for unit testing using the $componentController service. We also learned that Angular doesn’t trigger the different lifecycle hooks by itself, meaning that you need to manually call $onInit, etc.

In this post I’ll show an example for testing a component that makes use of the $onChanges hook.

Take a look at this simple word-counting component’s $onChanges hook:

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
app.component('wordCount', {
  template: `
    <div>
      <span ng-bind="$ctrl.words"></span> words
      <span ng-if="$ctrl.difference">
        <span ng-bind="$ctrl.difference"></span>
        since last save
      </span>
    </div>
  `,
  bindings: {
    text: '<'
  },
  controller: function() {
    this.$onChanges = (changes) => {
      if (changes.text) {
        this.words = countWords(this.text);
        if (changes.text.isFirstChange()) {
          this.difference = 0;
        } else {
          this.difference =
              this.words - countWords(changes.text.previousValue);
        }
      }
    };

    function countWords(text) {
      var trimmed = text.trim();
      if (trimmed.length === 0) return 0;
      return trimmed.split(/\s+/).length;
    }
  }
});

As you can see, the hook uses the changes object in order to know when the text has changes, detect the initial change, and also use the previousValue to calculate the word difference (yes, I know we could use the old words value, but this is just for the example).

You can see the component live here.

Now, testing this component is relatively trivial. We simply need to pass it some different values for text, trigger $onChanges, and that’s it. But, the fact is that Angular, for some reason, doesn’t expose the changes object it uses internally. That means that you’ll have to implement your own object that conforms to the changes object protocol–each changed property needs an isFirstChange method and 2 properties, currentValue and previousValue.

Since that’s a PITA, I’ve open sourced a tiny helper just for that, angular-stub-changes.

Using it, our tests now look 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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
describe('wordCount component', function() {
  var ctrl;

  beforeEach(function() {
    angular.mock.module(app);
    angular.mock.inject(function($componentController) {
      ctrl = $componentController('wordCount', null,
                {text: '1 2 3'});
    });
  });

  it('counts words', function() {
    var changes = new StubChanges().addInitialChange(
        'text', '1 2 3').build();
    ctrl.$onChanges(changes);

    expect(ctrl.words).toBe(3);
  });

  it('does not show difference when initializing', function() {
    var changes = new StubChanges().addInitialChange(
        'text', '1 2 3').build();
    ctrl.$onChanges(changes);

    expect(ctrl.difference).toBe(0);
  });

  it('calculates difference when changing text', function() {
    var changes = new StubChanges().addInitialChange(
        'text', '1 2 3').build();
    ctrl.$onChanges(changes);

    ctrl.text = '1 2 3 4 5';

    changes = new StubChanges().addChange(
        'text', '1 2 3 4 5', '1 2 3').build();
    ctrl.$onChanges(changes);

    expect(ctrl.difference).toBe(2);
  });
});

Basically, note that we make sure to call $onChanges with a properly configured changes object. Also, you still have to set the updated properties on your controller instance yourself, e.g. ctrl.text = '...'.

The creation of the stub changes object is, I hope, straightforward. It’s a builder pattern, so you can keep on adding how many changes (.addChange(..).addChange(..)) as needed for your component

That’s about it, happy testing!


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x

Unit Testing Angular Components with $componentController

| Comments

Angular 1.5+’s components are great, but testing them properly requires some changes to they way you were used to testing before.

Directives were always a bit clunky to test in Angular. You would either have to deal with recreating their DOM elements, or exposing the controller outside of the directive in order to test it directly. Since components are essentially wrappers around directives, you might expect the same dance.

But, along the introduction of components we also got the handy $componentController service. This service enables testing a component’s controller even without exposing it, and it also provides a simple way to supply a controller with bindings in the test.

Say that we have this component:

1
2
3
4
5
6
7
8
app.component('foo', {
  bindings: {
    baz: '<',
    bar: '<'
  },
  controller: function() {},
  templateUrl: 'foo.html'
});

In order to get an instance of foo’s controller in a test, we’d write this code:

1
2
3
4
var fooCtrl = $componentController('foo', null, {
  baz: 'baz value',
  bar: 'bar value'
});

As you can see, $componentController receives the name of the component that we’d like to test and also the bindings it should be initialized with, and returns the instantiated controller.

You can now start testing the controller, by invoking its functions and asserting the different results:

1
expect(fooCtrl.getDisplayResult()).to.equal('baz value bar value')

Don’t forget $onInit

In case your component implements the $onInit lifecycle hook, which is very likely starting from Angular 1.6, you should make sure to explicitly call it in your tests. Angular and $componentController does not take care of that for you, for different reasons.

This means that the test above should look like this:

1
2
3
var fooCtrl = $componentController('foo', null, {...});
fooCtrl.$onInit();
expect(fooCtrl.getDisplayResult()).to.equal('baz value bar value')

That’s it!

Handling $onChanges is even trickier in tests, make sure to subscribe below to get the next part about it.


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the next part about testing components and stay updated with the latest about modern Angular 1.x

Angular 1.6 is here: what you need to know

| Comments

Angular 1.6 was released a few weeks ago (and actually 1.6.1 was released a week ago). I’m so happy to see the Angular team keep spending time in making 1.x better and improving it.

As opposed to 1.5, 1.6 doesn’t introduce a lot of new features or changes, which I think is a good thing. I believe most 1.x projects have yet to integrate 1.5’s components properly, and so adding more changes might be overwhelming.

1.6 is more of a clean up release, that, in order to fix bugs and remove deprecations, introduces a handful of breaking changes.

I’ll go over the ones that I’m sure will trip a lot of people up. You can see the full, really long, list here.

Controller pre-assignment of bindings–or $onInit all the things

1.6 changes the default behavior of $compile in that it no longer, by default, initializes a controller’s bindings before $onInit is called (the new lifecycle hook introduced in 1.5, you can read more about it here).

What does that mean? Looking at this example:

1
2
3
4
5
6
7
8
app.component('foo', {
  bindings: {
    baz: '<'
  },
  controller: function() {
    this.baz.something();
  }
});

The above code will no longer work, since we’re accessing the baz binding inside the controller’s constructor function directly.

To change it to work, you should make sure to move all of your controller’s initialization code to be inside the $onInit hook:

1
2
3
4
5
6
7
8
9
10
app.component('foo', {
  bindings: {
    baz: '<'
  },
  controller: function() {
    this.$onInit = () => {
      this.baz.something();
    }
  }
});

Note: I’m using ES6 arrow functions for brevity.

In case you’ve already adopted your code to use $onInit you’re all good. Also, since most style guides, e.g. John Papa’s, have recommended the use of an init() function of sorts in controllers for quite a while, I’m assuming for most projects this is not a big deal. Simply rename your current init() functions to be $onInit methods.

What if you don’t want to go over all controllers right now?

In case you don’t have the time or energy to change all your controllers now, but still want to upgrade to 1.6, you can re-enable the old behavior:

1
2
3
app.config(function($compileProvider) {
  $compileProvider.preAssignBindingsEnabled(true);
});

But keep in mind that this is likely to be removed in a future version of Angular.

$onInit won’t work for standalone controllers

Standalone controllers are controllers that aren’t defined as part of a directive or component. Most commonly, these are controllers used as part of route definitions, or, heaven forbid, ng-controller.

Standalone controllers do not get the lifecycle hooks, and don’t have bindings anyway, so just make sure not to accidentally try and update them too in your migration frenzy. It won’t work.

$http.success and $http.error are finally gone

I’m really hoping not a lot of people are still using these relics of older Angular days, but I keep coming across projects that use it here and there (I believe old blog posts all over the web are at fault, most people aren’t aware of the difference when just starting).

I’ve written about why you shouldn’t be using them almost 2 years ago, and they’ve since been deprecated.

Well, 1.6 has finally killed them. If you’re still using them for some reason, here’s a great excuse to spend 20 minutes and use proper promises everywhere.

Upgrade and enjoy!


You want to do Angular the right way.
You hate spending time working on a project, only to find it’s completely wrong a month later.
But, as you try to get things right, you end up staring at the blinking cursor in your IDE, not sure what to type.
Every line of code you write means making decisions, and it’s paralyzing.

You look at blog posts, tutorials, videos, but each is a bit different.
Now you need to reverse engineer every advice to see what version of Angular it was written for, how updated it is, and whether it fits the current way of doing things.

What if you knew the Angular Way of doing things?
Imagine knocking down your tasks and spending your brain cycles on your product’s core.
Wouldn’t it be nice to know Angular like a second language?

You can write modern, clean and future-ready Angular right now.
Sign up below and get more of these helpful posts, free!
Always up to date and I’ve already done all the research for you.

And be the first the hear about my Modern Angular 1.x book – writing future proof Angular right now.

Subscribe to get the latest about modern Angular 1.x