Globally defined AngularJS controllers and encapsulation

According to AngularJS's tutorial, a controller function just sits within the global scope.

http://docs.angularjs.org/tutorial/step_04

Do the controller functions themselves automatically get parsed into an encapsulated scope, or do they dwell within the global scope? I know that they are passed a reference to their own $scope, but it appears that the function themselves are just sitting in the global scope. Obviously this can cause problems down the road, and I have learned through experience and education to encapsulate Further more, if they do dwell within the global scope, would it not be considered a best practice to encapsulate them within an object to be referenced like this:

    Object.functionName();

Rather than this:

    functionName();

So as to prevent issues that occur with the pollution of the global scope (ie overriding functions, etc..)

Answers:

Answer

AngularJS supports 2 methods of registering controller functions - either as globally accessible functions (you can see this form in the mentioned tutorial) or as a part of a modules (that forms a kind of namespace). More info on modules can be found here: http://docs.angularjs.org/guide/module but in short one would register a controller in a module like so:

angular.module('[module name]', []).controller('PhoneListCtrl', function($scope) {

  $scope.phones = [..];

  $scope.orderProp = 'age';
});

AngularJS uses a short, global-function form of declaring controllers in many examples but while this form is good for quick samples it rather shouldn't be used in real-life applications.

In short: AngularJS makes it possible to properly encapsulate controller functions but also exposes a simpler, quick & dirty way of declaring them as global functions.

Answer

You can register a controller as part of a module, as answered by pkozlowski-opensource.

If you need minification you can simply extend this by providing the variable names before the actual function in a list:

angular.module('[module name]', []).
  controller('PhoneListCtrl', ['$scope', function($scope) {

    $scope.phones = [..];
    $scope.orderProp = 'age';
  }]);

This will work the same after "minification":

angular.module('[module name]', []).
  controller('PhoneListCtrl', ['$scope', function(s) {

    s.phones = [..];
    s.orderProp = 'age';
  }]);

This notation can be found under "Inline Annotation" at Dependency Injection.

To test a controller, that has been registered as part of a module, you have to ask angular to create your controller. For example:

describe('PhoneListCtrl test', function() {
  var scope;
  var ctrl;

  beforeEach(function() {
    module('[module name]');
    inject(function($rootScope, $controller) {
      scope = $rootScope.$new();
      ctrl = $controller('[module name]', {$scope: scope});
    });
  });

  it('should be ordered by age', function() {
    expect(scope.orderProp).toBe('age');
  });

});

This method of testing the controller can be found under "Testing Controllers" at Understanding the Controller Component.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.