1. What is a Module?
Many applications have a main method for initialization, loading (Is wires meaning?) and launching applications. Angular application does not require the main method. Instead, module provides a declarative form with a specified purpose, descriptive description of how the application is started. There are several advantages to doing this:
2. The Basics
We are eager to know how to make Hello World module work. Here are a few key things to pay attention to:
module API (http://code.angularjs.org/1.0.2/docs/api/angular.Module)
Note the myApp module mentioned in <html ng-app="myApp">, which lets the launcher start the myApp module we defined.
<!DOCTYPE HTML><html lang="zh-cn" ng-app="myApp"><head> <meta charset="UTF-8"> <title>basics</title> <style type="text/css"> .ng-cloak { display: none; } </style></head><body><div> {{'Kitty' | greet}}</div><script src="../angular-1.0.1.js" type="text/javascript"></script><script type="text/javascript"> var simpleModule = angular.module("myApp", []); simpleModule.filter("greet", function () { return function(name) { return "Hello " + name + " !"; } });</script></body></html>3. (Recommended Setup) Recommended Setup
Although the above example is simple, it is not a large-scale application. We recommend splitting your application into multiple modules as follows:
The reason for this division is that when we are testing, we often need to ignore the initialization code that makes the test difficult. By dividing the code into separate modules, it is easy to ignore that code in tests. In this way, we can focus more on loading the corresponding module for testing.
The above is just a suggestion, you can make it as you want.
4. Module Loading & Dependencies (module loading and dependencies)
A module is a collection of configurations that execute blocks applied in the process of starting the application. In its simplest form, it consists of two types of blocks:
1. Configuration blocks: executed during the process of provider registration and configuration. Only provider and constant (constant?) can be injected into configuration blocks. This is to avoid the accident that the service is executed before the service is configured.
2. Run blocks: Execute after the injector is created and used to start the application. Only instances and constants can be injected into the run block. This is to avoid further system configuration execution during program operation.
angular.module('myModule', []). config(function(injectables) { // provider-injector // Here is an example of config block // We can get N such things as needed // We can inject Providers (not instances, not instances) into the config block}). run(function(injectables) { // instance-injector // Here is an example of run block // We can get N such things as needed // We can only inject instances (instances) (not Providers) into the run block});a) Configuration Blocks
There is a convenient way to do it in module, which is equivalent to config block. For example:
angular.module('myModule', []). value('a', 123). factory('a', function() { return 123; }). directive('directiveName', ...). filter('filterName', ...);// is equivalent to angular.module('myModule', []). config(function($provide, $compileProvider, $filterProvider) { $provide.value('a', 123) $provide.factory('a', function() { return 123; }) $compileProvider.directive('directiveName', ...). $filterProvider.register('filterName', ...);});The order in which configuration blocks are applied is consistent with the order in which they are registered. For constant definitions, it is an additional case, i.e., the constant definition placed at the beginning of configuration blocks.
b) Run Blocks (application block)
Run block is the closest thing to the main method in angular. The run block is the code that must be executed to start the application. It will be executed after all service configurations and injectors are created. Run blocks usually contain code that is more difficult to unit test. For this reason, these codes should be defined in a separate module so that they can be ignored in unit tests.
c) Dependencies (dependencies)
A module can list other modules it depends on. Relying on a module means that the requested module (reliable) must be loaded before requesting the module (the module that needs to depend on other modules, the requester) is loaded. In other words, the configuration block of the requested module will be executed before the configuration blocks or the requiring module, how to explain the or here?). The same is true for run block. Each module can only be loaded once, even if there are multiple other modules that require it.
d) Asynchronous Loading (asynchronous loading)
module is one of the ways to manage $injector configuration, without doing anything with loading scripts to the VM. There are now ready-made projects that are specifically designed for script loading, and can also be used in angular. Because modules do nothing during loading, they can be loaded into the VM in any order. Script loaders can use this feature to perform parallel loading.
5. Unit Testing
In the simplest form of unit testing, one is to instantiate a subset of an application in the test and then run them. Importantly, we need to realize that for each injector, each module will only be loaded once. Usually, an application only has one injector. But in tests, each test case has its injector, which means that in each VM, the module will be loaded multiple times. Building the module correctly will help unit testing, as in the following example:
In this example, we prepare to assume that the following module is defined:
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 test cases:
describe('myApp', function() { // Load the module of the application response, and then load the specified test module that rewrites $window to the mock version. // Do this, when window.alert() is performed, the tester will not stop because it is blocked by the real alert window // Here is an example of overwriting configuration information in the test beforeEach(module('greetMod', function($provide) {// It seems that the real $window is to replace the following $provide.value('$window', { alert: jasmine.createSpy('alert') }); })); // inject() will create an injector and inject greet and $window into the test. // The test does not need to care about how to write the application, it only needs to pay attention to how to test the application. it('should alert on $window', inject(function(greet, $window) { greet('World'); expect($window.alert).toHaveBeenCalledWith('Hello World!'); })); // Here is the method that overwrites the configuration through inline module and inject methods in the test 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!'); }); }); });