mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-21 01:57:06 +08:00
docs(guide/module): improve clarity
This commit is contained in:
@@ -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 `<html ng-app="myApp">`, it is what
|
||||
bootstraps the app using your module.
|
||||
I'm in a hurry. How do I get a Hello World module working?
|
||||
|
||||
<example module='myApp'>
|
||||
<file name="index.html">
|
||||
@@ -47,6 +47,13 @@ Important things to notice:
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Important things to notice:
|
||||
|
||||
* The {@link angular.Module Module} API
|
||||
* The reference to `myApp` module in `<html 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
|
||||
@@ -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.
|
||||
|
||||
<example module='xmpl'>
|
||||
<file name="index.html">
|
||||
@@ -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.
|
||||
<div class="alert alert-info">
|
||||
When bootstrapping, first Angular applies all constant definitions.
|
||||
Then Angular applies configuration blocks in the order same order they were registered.
|
||||
</div>
|
||||
|
||||
## 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', []);
|
||||
|
||||
// overwrites both myService and myDirective by creating a new module
|
||||
var myModule = angular.module('myModule', []);
|
||||
// add some directives and services
|
||||
myModule.service('myService', ...);
|
||||
myModule.directive('myDirective', ...);
|
||||
|
||||
// throws an error because myOtherModule has yet to be defined
|
||||
var myModule = angular.module('myOtherModule');
|
||||
// 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
|
||||
|
||||
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.
|
||||
|
||||
<div class="did you know...">
|
||||
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.
|
||||
</div>
|
||||
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user