codelord.net

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

Angular controllerAs: When Should You Use Scope

| Comments

Angular 2 is getting closer and so controllers are getting closer to death.

Using controllerAs syntax is the agreed way to prepare your code for the migration. But with all its awesomeness it makes some basic tasks tricky. Injecting $scope seems to be frowned upon.

Should you never use $scope again?
What about broadcasting events?
Listening for changes with $watch?
In what situations should you use it?

We’ll answer these questions in this post.

Recap: Previously I showed you how to refactor your existing controllers to make them easier to migrate to components. Then how to stop using them entirely.

These changes all rely on the awesome controllerAs syntax in Angular. This allows us to treat our directive controllers as objects and not use a 3rd party object, the scope, to pass along information.

Yet, scopes still have valid uses in the Angular world.

$watch

Sometimes, though hopefully rarely, you gotta write a $watch. Prior to controllerAs you’d write: $scope.$watch('foo', ...) and access $scope.foo.

Now that properties are exposed on the controller, e.g. using vm.foo = '123', this requires tweaking.

If our controller has a foo property and its controllerAs name is vm we can write: $scope.$watch('vm.foo', ...). That would work.

But… eww. I find this aesthetically displeasing. Nothing in your controller’s code should be aware of the controllerAs name it’s got. That knowledge is usually only used in the template.

That’s why I prefer to write the slightly longer:
$scope.$watch(function() {return self.foo;}, ...)

This decouples the controllerAs name and the controller’s code.

Events and broadcasting

Scopes come with the $emit, $broadcast and $on functions for interacting with events. Whenever you’re certain that events are the right tool for the job (which they usually aren’t) you should use this mechanism.

But, in a lot of situations there’s no need to use specific scopes with hierarchy for passing events. For example, if you want a generic PubSub event bus you can just use $rootScope alone across your system. I show a pattern for this here.

$apply

We have to call $scope.$apply() when running code in non-Angular contexts, like a jQuery plugin callback.

There’s no escaping this. If your code required $apply before moving to controllerAs you’re gonna have to keep doing it.

Like the previous point, though, you can just use the $rootScope. Calling $apply on any child scope has the same effect as calling it on the root scope. Using the $rootScope in these situations makes it clear that it is being used for something global.

For anything else, don’t use scope

It’s that simple. Kick controllers’ butt!

“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