Improve this DocModules

From Get docs
< Improve this DocGuide to AngularJS DocumentationAngularjs/docs/1.8/guide/module


Improve this DocModules

What is a Module?

You can think of a module as a container for the different parts of your app – controllers, services, filters, directives, etc.

Why?

Most applications have a main method that instantiates and wires together the different parts of the application.

AngularJS apps don't have a main method. Instead modules declaratively specify how an application should be bootstrapped. There are several advantages to this approach:

  • The declarative process is easier to understand.
  • You can package code as reusable modules.
  • The modules can be loaded in any order (or even in parallel) because modules delay execution.
  • Unit tests only have to load relevant modules, which keeps them fast.
  • End-to-end tests can use modules to override configuration.

The Basics

I'm in a hurry. How do I get a Hello World module working?

Important things to notice:

  • The Module API
  • The reference to myApp module in <div ng-app="myApp">. This is what bootstraps the app using your module.
  • The empty array in angular.module('myApp', []). This array is the list of modules myApp depends on.

Recommended Setup

While the example above is simple, it will not scale to large applications. Instead we recommend that you break your application to multiple modules like this:

  • A module for each feature
  • A module for each reusable component (especially directives and filters)
  • And an application level module which depends on the above modules and contains any initialization code.

You can find a community style guide to help yourself when application grows.

The above is a suggestion. Tailor it to your needs.

Module Loading

A module is a collection of providers, services, directives etc., and optionally config and run blocks which get applied to the application during the bootstrap process.

The module API describes all the available methods and how they can be used.

See Using Dependency Injection to find out which dependencies can be injected in each method.

Dependencies and Order of execution

Modules can list other modules as their dependencies. Depending on a module implies that the required module will be loaded before the requiring module is loaded.

In a single module the order of execution is as follows:

  1. provider functions are executed, so they and the services they define can be made available to the $injector.
  2. After that, the configuration blocks (config functions) are executed. This means the configuration blocks of the required modules execute before the configuration blocks of any requiring module.

This continues until all module dependencies has been resolved.

Then, the run blocks that have been collected from each module are executed in order of requirement.

Note: each module is only loaded once, even if multiple other modules require it. Note: the factory function for "values" and "services" is called lazily when the value/service is injected for the first time.

Registration in the config block

While it is recommended to register injectables directly with the module API, it is also possible to register services, directives etc. by injecting $provide or the individual service providers into the config function:

angular.module('myModule', []).
  value('a', 123).
  factory('a', function() { return 123; }).
  directive('directiveName', ...).
  filter('filterName', ...);

// is same as

angular.module('myModule', []).
  config(function($provide, $compileProvider, $filterProvider) {
    $provide.value('a', 123);
    $provide.factory('a', function() { return 123; });
    $compileProvider.directive('directiveName', ...);
    $filterProvider.register('filterName', ...);
  });

Run Blocks

Run blocks are the closest thing in AngularJS to the main method. A run block is the code which needs to run to kickstart the application. It is executed after all of the services have been configured and the injector has been created. Run blocks typically contain code which is hard to unit-test, and for this reason should be declared in isolated modules, so that they can be ignored in the unit-tests.

Asynchronous Loading

Modules are a way of managing $injector configuration, and have nothing to do with loading of scripts into a VM. There are existing projects which deal with script loading, which may be used with AngularJS. Because modules do nothing at load time they can be loaded into the VM in any order and thus script loaders can take advantage of this property and parallelize the loading process.

Creation versus Retrieval

Beware that using angular.module('myModule', []) will create the module myModule and overwrite any existing module named myModule. Use angular.module('myModule') to retrieve an existing module.

var myModule = angular.module('myModule', []);

// add some directives and services
myModule.service('myService', ...);
myModule.directive('myDirective', ...);

// overwrites both myService and myDirective by creating a new module
var myModule = angular.module('myModule', []);

// throws an error because myOtherModule has yet to be defined
var myModule = angular.module('myOtherModule');

Unit Testing

A unit test is a way of instantiating a subset of an application to apply stimulus to it. Small, structured modules help keep unit tests concise and focused.

Each module can only be loaded once per injector. Usually an AngularJS app has only one injector and modules are only loaded once. Each test has its own injector and modules are loaded multiple times.

In all of these examples we are going to assume this module definition:

angular.module('greetMod', []).

factory('alert', function($window) {
  return function(text) {
    $window.alert(text);
  }
}).

value('salutation', 'Hello').

factory('greet', function(alert, salutation) {
  return function(name) {
    alert(salutation + ' ' + name + '!');
  }
});

Let's write some tests to show how to override configuration in tests.

describe('myApp', function() {
  // load application module (`greetMod`) then load a special
  // test module which overrides `$window` with a mock version,
  // so that calling `window.alert()` will not block the test
  // runner with a real alert box.
  beforeEach(module('greetMod', function($provide) {
    $provide.value('$window', {
      alert: jasmine.createSpy('alert')
    });
  }));

  // inject() will create the injector and inject the `greet` and
  // `$window` into the tests.
  it('should alert on $window', inject(function(greet, $window) {
    greet('World');
    expect($window.alert).toHaveBeenCalledWith('Hello World!');
  }));

  // this is another way of overriding configuration in the
  // tests using inline `module` and `inject` methods.
  it('should alert using the alert service', function() {
    var alertSpy = jasmine.createSpy('alert');
    module(function($provide) {
      $provide.value('alert', alertSpy);
    });
    inject(function(greet) {
      greet('World');
      expect(alertSpy).toHaveBeenCalledWith('Hello World!');
    });
  });
});

© 2010–2020 Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
https://code.angularjs.org/1.8.2/docs/guide/module