Published using Google Docs
Scope/controller separation
Updated automatically every 5 minutes

Separating scope / controller Proposal

Problems we want to solve

No private state for controllers (prototype definition)

When creating controllers as types using the prototype definition (google style guide), the only way to pass reference from the constructor to a method is by assigning it to `this`. Since `this` is also the scope, we end up with lot of stuff being published into template:

var Controller = function($location, $parse, $compile) {

  // all of these are published into template !!!

  this.$location = $location;

  this.$parse = $parse;

  this.$compile = $compile;

};

Controller.prototype.method = function() {

  // but they are actually used only in controller’s methods

};

What’s even worse, that this leads to `scope` being used as a communication layer between nested controllers.

See https://cs.corp.google.com/#google3/java/com/google/ads/xfa/site/app/controllers/app.js

App controller has 10 dependencies and they are used by various nested controllers through scope inheritance. This information is stored in template, so if you want to test any child controller, you have to mimic the scope hierarchy created by the template. Additionally when looking at child controllers, it's often not obvious where various dependencies came from unless you are familiar with the inheritance hierarchy.

No proper controller instantiation

Currently we don’t instantiate controllers. We copy their prototype methods (and bind them) to scope and apply the constructor function onto the scope.

With separating scope from controller, we can instantiate controller using `new` operator and inject related `scope` - both these problems are gone.

Clear separation of stuff that’s published in the template

See this readability conversation: https://critique.corp.google.com/#review/25563789

We can see this problem on DFA, Feedback an probably other projects as well. It’s difficult to know, which properties are used in templates and which not. We want to make this clear - transparent.

Only the stuff published for templating should be on the `scope` object.

Better / easier compilation with Closure Compiler

All methods / properties on controller can be renamed, only scope needs to be preserved, because all scope properties are actually used in the template. We can provide `scope` type, that compiler will recognise automatically and won’t rename its properties.

Using `var scope = this;` all the time

In constructor definition style, we can get rid off these completely.

var Controller = function($scope, $http) {

  this.method = function() {

    $http.get(...).then(function(data) {

      $scope.data = data;

    });

  };

};

Example

https://gist.github.com/1470651

Backward compatibility

`$controller` service is responsible for instantiating controllers, so whenever `ng:controller` or `$route` need to create new controller, they ask `$controller` service for it. That means, if someone really wants to have the original behavior, he can easily override this service to get it back.

This might be temporary solution for DFA and other applications, but I would prefer to avoid doing it at all.

Explaining terms

Prototype definition style (Google style):

var Controller = function() {

};

Controller.prototype.method = function() {};

Constructor definition style

var Controller = function() {

  this.method = function() {};

};