codelord.net

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

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.

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Comments