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.
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.
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.
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.
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;
});
};
};
https://gist.github.com/1470651
`$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.
var Controller = function() {
};
Controller.prototype.method = function() {};
var Controller = function() {
this.method = function() {};
};