0

A few months back I read this article about not using ng-controller and adopted the idea behind it: that angular apps should be sets of components working together.

The basic idea was that you would use isolate scope directives with their own controllers like this:

.directive('myAppContestantList', function() {
    return {
      scope: {},
      templateUrl: 'my_app_contestant_list.html',
      replace: true,
      controller: 'ContestantListCtrl',
      controllerAs: 'ctrl'
    };
  })
  .controller('ContestantListCtrl', function() {
    this.contestants = [
      {firstName: 'Rachel', lastName: 'Washington'},
      {firstName: 'Joshua', lastName: 'Foster'},
      {firstName: 'Samuel', lastName: 'Walker'},
      {firstName: 'Phyllis', lastName: 'Reynolds'}
    ];
  });

and instead of making your a data property of $scope in your controller, you made it a property of this (this being the controller itself). Defining variables on the controller meant you could reference your data in your html just by prefixing your data with ctrl because that's what you put in the controllerAs field:

<li ng-repeat="contestant in ctrl.contestants">
    {{contestant.firstName}} {{contestant.lastName}}
</li>

This worked perfectly fine for me, and I began nesting directives instead of nesting controllers, which solved the nested $scope problem.

Given that background, what I don't understand is why the article advocates defining variables on your controller instead of on $scope. It's true that previously $scope was a huge problem because once you had nested scopes it would be a mess, but using the pattern it advocates of isolated scope directives, variables defined on $scope never leak.

You would also never find yourself in the position where there would be more than one controller in the template so controllerAs seems useless as well.

I say this after being very successful using the pattern for a few months with variables defined on my controller. I'd just like to know if/why it's better to do that than define them on $scope instead of blindly following along with the article.

Does it possibly have to do with bindToController?

Could someone point me in the right direction?

m0meni
  • 16,006
  • 16
  • 82
  • 141

1 Answers1

1

It is true that 'controllerAs + this' recipe is primarily targeted at complex templates that introduce multiple ng-controller and other built-in directives, so controller identifiers deal with scope inheritance quite nicely.

Directives with isolated scope on the other side assume that attributes are primarily used to interact with parent scope, it raises no issues with scope inheritance, and $scope feels itself great there.

In the second case it is unpractical to get rid of $scope just to make the code look more like Angular2, AngularJS was designed with scope in mind after all. The article that was mentioned in the question is a good example of overzealous scope persecution, it got too much attention in the community IMO.

Here is a concise example of a directive:

app.directive('isolated', function () {
  return {
    scope: {
      'isolated': '@'
    },
    template: '{{::data}}',
    controller: function ($scope) {
      $scope.data = $scope.isolated + '!';
    },
    link: function (scope, element) {
      element.append("<br>DOM " + scope.data);
    }
  };
});

And the directive can be 'improved' by eliminating 'scope' by all means:

app.directive('isolated', function () {
  return {
    scope: { // yikes!
      'isolated': '@'
    },
    template: '{{::vm.data}}',
    controller: function () {
      this.data = this.isolated + '!';
    },
    controllerAs: 'vm',
    bindToController: true,
    link: function (s___e, element, attrs, ctrl) {
      element.append("<br>DOM " + ctrl.data);
    }
  };
});

Due to bindToController it becomes a little less verbose, and only the template is polluted with controller identifiers. This transformation looks useless but some time may be saved if there's a chance that the template will end up with a bunch of ng-repeats.

There may be other unobvious use cases for both syntaxes. E.g. controller this statements can be abstracted to separate service with zero effort (but sporadic $scope.$... is a killjoy).

TL;DR: this works best in conjunction with controllerAs syntax if the code relies on 'HTML programming' and directives with inherited scopes, but it is rarely a must when app is composed of web component-like directives with isolated scopes, methinks.

Community
  • 1
  • 1
Estus Flask
  • 206,104
  • 70
  • 425
  • 565