aboutsummaryrefslogtreecommitdiffstats
path: root/docs/content/guide/module.ngdoc
diff options
context:
space:
mode:
authorMisko Hevery2012-02-23 09:53:14 -0800
committerMisko Hevery2012-02-23 09:53:14 -0800
commit5d8528cc2e1092cdd9533f8c9f0d716200e88b7e (patch)
tree079d86d11b9645d71bd130f4469b10bbeef22f7b /docs/content/guide/module.ngdoc
parent80edcadb1dd418dcf5adf85704c6693940c8bb28 (diff)
downloadangular.js-5d8528cc2e1092cdd9533f8c9f0d716200e88b7e.tar.bz2
docs(module): Describe module loading
Diffstat (limited to 'docs/content/guide/module.ngdoc')
-rw-r--r--docs/content/guide/module.ngdoc258
1 files changed, 258 insertions, 0 deletions
diff --git a/docs/content/guide/module.ngdoc b/docs/content/guide/module.ngdoc
new file mode 100644
index 00000000..12ec8917
--- /dev/null
+++ b/docs/content/guide/module.ngdoc
@@ -0,0 +1,258 @@
+@ngdoc overview
+@name Developer Guide: Modules
+@description
+
+# What is a Module?
+
+Most applications have a main method which instantiates, wires, and bootstraps the application.
+Angular apps don't have a main method, instead the modules serves the purpose of declaratively
+specifying 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 Basics
+
+Ok i am in a hurry how do i get a Hello World module working?
+
+Important things to notice:
+
+ * {@link api/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.
+
+<doc:example module='simpleApp'>
+ <doc:source>
+ <script>
+ // declare a module
+ var simpleAppModule = angular.module('simpleApp', []);
+
+ // configure the module.
+ // in this example we will create a greeting filter
+ simpleAppModule.filter('greet', function() {
+ return function(name) {
+ return 'Hello, ' + name + '!';
+ };
+ });
+
+ </script>
+ <div>
+ {{ 'World' | greet }}
+ </div>
+ </doc:source>
+</doc:example>
+
+
+
+# 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 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
+ 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 separate module it
+can be easily ignored in tests. The tests can also be more focused by only loading the modules
+which are relevant to tests.
+
+The above is only a suggestion, so feel free to tailor it to your needs.
+
+<doc:example module='xmpl'>
+ <doc:source>
+ <script>
+ angular.module('xmpl.service', []).
+ value('greeter', {
+ salutation: 'Hello',
+ localize: function(localization) {
+ this.salutation = localization.salutation;
+ },
+ greet: function(name) {
+ return this.salutation + ' ' + name + '!';
+ }
+ }).
+ value('user', {
+ load: function(name) {
+ this.name = name;
+ }
+ });
+
+ angular.module('xmpl.directive', []);
+
+ angular.module('xmpl.filter', []);
+
+ angular.module('xmpl', ['xmpl.service', 'xmpl.directive', 'xmpl.filter']).
+ run(function(greeter, user) {
+ // This is effectively part of the main method initialization code
+ greeter.localize({
+ salutation: 'Bonjour'
+ });
+ user.load('World');
+ })
+
+
+ // A Controller for your app
+ var XmplController = function($scope, greeter, user) {
+ $scope.greeting = greeter.greet(user.name);
+ }
+ </script>
+ <div ng-controller="XmplController">
+ {{ greeting }}!
+ </div>
+ </doc:source>
+ </doc:example>
+
+
+
+# Module Loading & Dependencies
+
+A module is a collection of configuration and run block which get applied to the application
+during the bootstrap process. In its simplest form the module consist of collection of two kinds
+of blocks:
+
+ 1. **Configuration blocks** - get executed during the provider registrations and configuration
+ phase. Only providers and constants can be injected into configuration blocks. This is to
+ prevent accidental instantiation of services before they have been fully configured.
+ 2. **Run blocks** - get executed after the injector is created and are used to kickstart the
+ application. Only instances and constants can be injected into run blocks. This is to prevent
+ further system configuration during application run time.
+
+<pre>
+angular.module('myModule', []).
+ config(function(injectables) { // provider-injector
+ // 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.
+ }).
+ 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)
+ // int the run blocks
+ });
+</pre>
+
+## Configuration Blocks
+
+There are some convenience methods on the module which are equivalent to the config block. For
+example:
+
+<pre>
+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', ...);
+ });
+</pre>
+
+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.
+
+## Run Blocks
+
+Run blocks are the closest thing in Angular 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 service 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.
+
+## Dependencies
+
+Modules can list other modules as their dependencies. Depending on a module implies that required
+module needs to be loaded before the requiring module is loaded. In other words the configuration
+blocks of the required modules execute before the configuration blocks or the requiring module.
+The same is true for the run blocks. Each module can only be loaded once, even if multiple other
+modules require it.
+
+## 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 Angular. 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 paralyze the loading process.
+
+
+# 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:
+
+In all of these examples we are going to assume this module definition:
+<pre>
+ 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 + '!');
+ }
+ });
+</pre>
+
+Let's write some tests:
+<pre>
+describe('myApp', function() {
+ // load the application relevant modules then load a special
+ // test module which overrides the $window with 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.
+ 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.
+ 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.
+ 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('World');
+ });
+ });
+});
+</pre>