From d07101dec08a698932ef0aa2fc36316d6f7c4851 Mon Sep 17 00:00:00 2001 From: Brian Ford Date: Mon, 3 Mar 2014 12:51:56 -0800 Subject: docs(guide/module): improve clarity --- docs/content/guide/module.ngdoc | 135 +++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 64 deletions(-) diff --git a/docs/content/guide/module.ngdoc b/docs/content/guide/module.ngdoc index 747209c2..e2925584 100644 --- a/docs/content/guide/module.ngdoc +++ b/docs/content/guide/module.ngdoc @@ -4,27 +4,27 @@ # What is a Module? -Most applications have a main method which instantiates, wires, and bootstraps the application. +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. + Angular 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 process is more declarative which is easier to understand - * In unit-testing there is no need to load all modules, which may aid in writing unit-tests. - * Additional modules can be loaded in scenario tests, which can override some of the - configuration and help end-to-end test the application - * Third party code can be packaged as reusable modules. - * The modules can be loaded in any/parallel order (due to delayed nature of module execution). + * 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 -Ok, I'm in a hurry. How do I get a Hello World module working? - -Important things to notice: - - * {@link angular.Module Module} API - * Notice the reference to the `myApp` module in the ``, it is what - bootstraps the app using your module. +I'm in a hurry. How do I get a Hello World module working? @@ -47,6 +47,13 @@ Important things to notice: +Important things to notice: + + * The {@link angular.Module Module} API + * The reference to `myApp` module in ``. + 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 @@ -54,18 +61,15 @@ Important things to notice: 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 service module, for service declaration - * A directive module, for directive declaration - * A filter module, for filter declaration - * And an application level module which depends on the above modules, and which has + * 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. -The reason for this breakup is that in your tests, it is often necessary to ignore the -initialization code, which tends to be difficult to test. By putting it into a separate module it -can be easily ignored in tests. The tests can also be more focused by only loading the modules -that are relevant to tests. +We've also written a document on how we organize large apps at Google and on how to write +reusable components. -The above is only a suggestion, so feel free to tailor it to your needs. +The above is a suggestion. Tailor it to your needs. @@ -133,19 +137,19 @@ angular.module('myModule', []). // This is an example of config block. // You can have as many of these as you want. // You can only inject Providers (not instances) - // into the config blocks. + // into config blocks. }). run(function(injectables) { // instance-injector // This is an example of a run block. // You can have as many of these as you want. // You can only inject instances (not Providers) - // into the run blocks + // into run blocks }); ``` ## Configuration Blocks -There are some convenience methods on the module which are equivalent to the config block. For +There are some convenience methods on the module which are equivalent to the `config` block. For example: ```js @@ -166,8 +170,10 @@ angular.module('myModule', []). }); ``` -The configuration blocks get applied in the order in which they are registered. The only exception -to it are constant definitions, which are placed at the beginning of all configuration blocks. +
+When bootstrapping, first Angular applies all constant definitions. +Then Angular applies configuration blocks in the order same order they were registered. +
## Run Blocks @@ -198,72 +204,73 @@ Beware that using `angular.module('myModule', [])` will create the module `myMod existing module named `myModule`. Use `angular.module('myModule')` to retrieve an existing module. ```js - var myModule = angular.module('myModule', []); - - // add some directives and services - myModule.service('myService', ...); - myModule.directive('myDirective', ...); +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', []); +// 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'); +// throws an error because myOtherModule has yet to be defined +var myModule = angular.module('myOtherModule'); ``` # Unit Testing -In its simplest form a unit test is a way of instantiating a subset of the application in test and -then applying a stimulus to it. It is important to realize that each module can only be loaded -once per injector. Typically an app has only one injector. But in tests, each test has its own -injector, which means that the modules are loaded multiple times per VM. Properly structured -modules can help with unit testing, as in this example: +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 Angular 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: ```js - angular.module('greetMod', []). +angular.module('greetMod', []). - factory('alert', function($window) { - return function(text) { - $window.alert(text); - } - }). + factory('alert', function($window) { + return function(text) { + $window.alert(text); + } + }). - value('salutation', 'Hello'). + value('salutation', 'Hello'). - factory('greet', function(alert, salutation) { - return function(name) { - alert(salutation + ' ' + name + '!'); - } - }); + factory('greet', function(alert, salutation) { + return function(name) { + alert(salutation + ' ' + name + '!'); + } + }); ``` -Let's write some tests: +Let's write some tests to show how to override configuration in tests. ```js describe('myApp', function() { - // load the relevant application modules then load a special - // test module which overrides the $window with a mock version, - // so that calling window.alert() will not block the test - // runner with a real alert box. This is an example of overriding - // configuration information in tests. + // 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') }); })); - // The inject() will create the injector and inject the greet and - // $window into the tests. The test need not concern itself with - // wiring of the application, only with testing it. + // 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 an inline module and inject methods. + // tests using inline `module` and `inject` methods. it('should alert using the alert service', function() { var alertSpy = jasmine.createSpy('alert'); module(function($provide) { -- cgit v1.2.3