You’re chugging along great with your Angular app, following John Papa’s Style Guide like you’ve heard you should be. Then you run into a problem.
You found a solution on some blog but oh crap! It’s using $scope
all over the place! How can you pull it into your code without polluting your well-styled masterpiece?
Here we’ll cover a couple quick things you can do to transform a $scope’d mess into a sparkling paragon of virtuous code.
$scope
becomes controllerAs
Start with a controller using $scope:
Transform it!
- [controller] Add
vm = this
at the top. - [controller] Find/replace
$scope
withvm.
- [view] Add
as someName
to anyng-controller
s. - [view] Prepend
someName.
to all variables.
Here’s that example again, fixed up to use controllerAs:
Notice that the view refers to the controller as “app”, while the controller refers to itself as “vm”. These names don’t affect each other.
Using $watch
with controllerAs
What if you need to $watch or $broadcast from the controller? You can’t do it without $scope!
This is ok though – think of $scope as a service in this case. It’s giving you access to special behavior. You won’t use it to pass data to/from the view.
Here’s it is with $scope:
Transform it!
(only step 3 is new from before)
- [controller] Add
vm = this
at the top. - [controller] Find/replace
$scope
withvm.
- [controller] Prefix watched vars with the controller name from the view. (
app.
in this case) - [view] Add
as someName
to anyng-controller
s. - [view] Prepend
someName.
to all variables.
Here’s the controllerAs version:
Now you know how to mechanically transform tutorials that use $scope into cleaner code that uses controllerAs!
So $scope is vanquished now, right?
Well, not quite. $scope never truly dies. Read on…
Behind The Scenes
Here’s what the $scope hierarchy looks like normally:
When you refer to users
in your view, Angular looks on $scope
for it. If it’s not there, it will look to the prototypical parent, which is $rootScope
.
If there were any intermediate $parent
scopes, it would check those before checking $rootScope
.
It’s a plain old JavaScript prototypical inheritance tree: Check children first, then walk up the tree until the variable is found.
Here’s that same variable nested under a controllerAs-style controller named ctrl
:
You write UserCtrl as ctrl
in your view and Angular inserts the controller itself onto $scope
, as $scope.ctrl
. What was previously just user
is now ctrl.user
.
This is why, when setting up a $watch, “name” became “app.name” – everything is still a descendant of $scope
, but variables are now nested inside a named controller.
Clarity at last
Hopefully this cleared up some confusion around using tutorials out on the web.
As always, the best way to internalize this stuff is to practice.
Remember: There are no shortcuts, ONLY ZUUL! I mean practice. Only practice.