Understanding Modules in AngularJS

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.

According to AngularJS documentation, a module is defined as a collection of services, directives, controllers, filters, and configuration information.

There are several advantages of using modules:

  • 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 following code demonstrates how to create a module:

In the above code, we’ve declared a module named myModule using the inbuilt angular.module function. Notice that we’ve passed an empty array to it. This array generally contains dependent modules.

It is recommended that we have a module for each reusable component (especially directives and filters)

To load an existing module, we use the following syntax:

Notice that when we load a module, we do not specify the dependencies. So, loading the module is similar to creating one except that we do not specify an array of dependencies.

Once you have created a module, you can add controllers, services, filters, etc to it.

The code above shows how to add a controller (TodoController in this case) to an existing module. Similarly, you can add services, filters, etc. to a module.

Modules in AngularJS

Talking about modules, there are two other important concepts that needs attention. They are the Configuration and Run blocks. These blocks of code get executed at different points in the application bootstrap, and have different injection locals at their disposal.

Configuration & Run blocks

Configuration blocks (registered with module.config()) get executed during provider registration, and only providers and constants can be injected. This is typically where you would configure application-wide stuff, such as the $routeProvider. Typically, the stuff that needs to be configured before the services are created are configured in this block.

Run blocks (registered with module.run()) get executed after the injector has all the providers. This is typically where you would configure services, $rootScope, events and so on. This is like the main() method in other languages that you might have come across.

Config block example:

Run block example:

Grouping Modules

Now that we understand it is a best practice to split our application into different modules, the next question that arises is “what’s the best boundary for this split“? We can primarily think of two options. Splitting the application into separate parts for directives, for controllers, filters, etc Or to group our modules based on functionality. The general consensus, also shared by members of the AngularJS team is to group our source code into modules based on functionality.

This approach allows us to create re-usable components at the base of our application (or even at the base of multiple applications), to re-use existing modules which have been created by others, and then to add modules which group functional parts of our application.