AngularJS Architecture: Prefer the 'controller as' syntax

Lukas Ruebbelke
InstructorLukas Ruebbelke

Share this video with your friends

Send Tweet
Published 8 years ago
Updated 4 months ago

As of Angular 1.2, the use of $scope injectable has been greatly reduced in favor of the "controller as syntax". We are going to take a quick look at cleaning up Eggly to follow this best practice.

[00:02] Hello. In this lesson, we are going to press pause for just a moment, address the issue of scope inheritance, and then do a quick refactor to fix it before we get into our models. Let's see what the problem is. Let's hop into our bookmarks.js file.

[00:23] You can see that we are only binding to one property on scope. That is currentCategoryName. With that in mind, let's hop into the bookmarks template. You can see that we are binding to this property, currentCategory, right here.

[00:44] The question is "What about all these other things that we're binding to?" For instance, this bookmarks collection in ng-repeat or these methods that we're binding to in ng-click. Where do those exist? Obviously, they're not in the bookmarks controller.

[01:05] The answer to that question is they are in this main controller here. You can see the bookmarks collection, these different methods that we're making available onto the main controller and then making it available on the body tag. It's the top-most controller.

[01:28] In AngularJS, scope objects prototypically inherit from their parent scope object all the way up to root scope. This creates an interesting situation where the main controller is the parent controller to the bookmarks controller.

[01:51] We are implicitly attaching the scope object or the properties or methods from main controller onto the scope object of the bookmarks controller. This may seem convenient at first, but when you have an application that's growing in size and complexity, this implicit inheritance is just a recipe for unintended consequences.

[02:19] For instance, what would happen if I changed a property on this bookmarks collection and this URL property actually got changed to local URL or some other property?

[02:35] This template would break, and you wouldn't be able to understand why by looking at the bookmarks controller because you have this implicit scope inheritance. You're actually pulling from a property that is much further up the prototype chain.

[02:52] We are going to fix this problem using the "controller as" syntax. This allows us to convert our controller to appear JavaScript object, and we no longer have to use scope as the glue between our controller and our view.

[03:13] The first thing we're going to do is jump into our state definition and just go "BookmarksCtrl as bookmarks." In our bookmarks controller, we are going to delete the scope object.

[03:29] I am going to create a variable called "bookmarks" and just assign it to "this." This is just a convention that I like to use. It also keeps track of the top-level JavaScript scope in case you have nested callbacks or closures. We'll just go here.

[03:47] Now, we have assigned currentCategory to bookmarks. Let's go back to our template. It's now bookmarks.currentCategoryName. Now, this reads a little bit better, and it's a little bit more precise of where currentCategoryName is coming from.

[04:12] It's on the bookmarks object that we defined in our state definition. It's "BookmarksCtrl as bookmarks," and then we're referencing this property, currentCategoryName, on bookmarks. Let's refresh the page. Let's go to Development. You can see that this is still working.

[04:36] The interesting thing is the implicit inheritance chain is broken. Now, we're no longer reaching out of our controller into a parent controller and pulling down the bookmarks collection, which is why in the next lesson we are going to actually explicitly provide that to our bookmarks controller in the bookmarks model and make that available. Stay tuned for the next lesson. I'll see you then.

mifprojects
mifprojects
~ 8 years ago

Hello Lukas! I want to ask you, is there a good way to use some variable from parent state ctrl in child state ctrl using the controller as syntax? For example using $scope way I have scope inheritance so it works fine, but how it could be done using new controller as syntax? Thanks!

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 8 years ago

Hello -- I recommend checking out Todd Motto's excellent article on 'controller as' syntax here http://toddmotto.com/digging-into-angulars-controller-as-syntax/. Check out the section on nested scopes as he locks it down perfectly from the template side.

In terms of JavaScript, I would promote that variable to a service and share it between the two controllers which I cover in the next lesson. I would do my best to avoid implicit inheritance as it couples your two controllers together which makes extensibility and testing really hard.

Does this make sense?

mifprojects
mifprojects
~ 8 years ago

Thanks for answering. I think you are right and it make sense. Will wait next videos! Thanks :)

Frank Stepanski
Frank Stepanski
~ 7 years ago

I did the same code, but do not get the updated information in the <H1>..any ideas?

http://angularjs.javascriptworkshop.com/lesson7/step13/index.html#/categories/Development

Frank Stepanski
Frank Stepanski
~ 7 years ago

nevermind....dumb caching :)