Angular modules are designed to distribute our application into blocks of different modules which are more manageable. As our application starts growing incorporating more features and functionalities, it becomes tedious to manages if we keep on adding code into our single block of application. Then there comes a time when we have to code our new big features into a different module. We then use that module in our main application module.
Angular modules are independent block of distributable code. These can be exported as a library. For e.g. Angular provides us with BrowserModule, HttpModule, FormsModule etc. Similarly we can make our own Angular module which can be used in one or more application depending on the scope of functionality which we are building,
It is much easier to do with Angular Modules.
An Angular Module is a class with ngModule decorator.
Features of and Angular module
- It declares its own set of Components, Directives and Pipes.
- It can be exported as an angular module where other modules con consume its components, directives and pipes.
- It provide services to itself and other modules.
- It can import other modules in its own module declaration and use their components, directives and pipes.
If we look at our default app.module.ts file, we will find something similar code like this:
import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
export class App {
constructor() {
}
}
NgModule({
imports: [ BrowserModule ],
declarations: [ App],
providers : [],
bootstrap: [ App ]
})
export class AppModule {}
The @ngModule() directive have some different sets of settings. Let's look at them one by one.
imports
This is an array where we define other modules that we want to import in our main application module such as BrowserModule, FormsModule or any other third party module. One thing to note that when we export our module, all other modules that we imported are also available in our exported module. If A import B and C imports A, this means C does not have access to B.
declaration
This is an array which defines all the components, directives, pipes that belong to our angular module. Each of them must belong to only one angular module.
bootstrap
This is used to load the application module in Angular ecosystem. The application must bootstrap at least one component which is the root application component. It should only be used in the root application module.
exports
This is an array that is used to export components, directives and pipes to other module.
providers
This is an array where we define services of our module. This can be either at root level or any component level. If we have defined our service in providers array at root level, then that service will also be available to all child components. If we want a service available to a particular component only then we define that service to that component's provider array only.
Feature Module
A Feature Module in Angular is a module other than our main application root module that is decorated by @ngModule() decorator and hence share the same property configurations like application root module. You can also say it a custom module or an external module, but Feature Module is an Angular way of saying wherein we separate our features of our main application into a different module.
As our application starts growing bigger, it's better to re-factor at early stage so that the application stays manageable. Implementing Feature modules is a way of re-factoring our application.
Example application - Mail Client
Ok, so now we will move on to building an example application which is Mail Client. We will introduce two Feature modules - Mail Box and Address Book in our main application root module i.e. Mail Client.
MailClient component
Here we are just showing the version of the mail client which we input from main application component.
import {Component, Input} from '@angular/core'
@Component({
selector: 'mail-client',
template: `
<div>
<h2>MailClient : v - </h2>
</div>
`
})
export class MailClient {
@Input() version:number;
constructor(){
}
}
MailBox Feature module
This is our MailBox Feature Module which have a MailBox component and a MailBox service
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MailBoxComponent } from './mailBox.component'
import { MailBoxService } from './mailBox.service'
@NgModule({
imports: [ CommonModule ],
declarations: [ MailBoxComponent ],
exports: [ MailBoxComponent ],
providers: [ MailBoxService ]
})
export class MailBoxModule { }
MailBox Service
It contains one method which provides inbox mails (values hard-codes for demo, can be extended).
import {Injectable} from '@angular/core'
@Injectable()
export class MailBoxService {
constructor(){
}
getInboxMails():string[] {
return [
"Welcome to MailClient",
"Daily Newsletter",
"20% discount on this product"
];
}
}
MailBox component
It displays all the mails provided by the MailBox Service.
import { Component } from '@angular/core'
import { MailBoxService } from './mailBox.service'
@Component({
selector: 'mail-box',
template: `
<div>
<h2>Mail Box</h2>
<div ngFor='let ibMail of inboxMails; let idx = index'>
<div>{{idx+1}} - {{ibMail}}</div>
</div>
</div>
`
})
export class MailBoxComponent implements OnInit{
inboxMails:string[];
constructor(private _service: MailBoxService){
}
ngOnInit(){
this.inboxMails = this._service.getInboxMails();
}
}
AddressBook Feature Module
In the similar way, we will create another Feature module - Address Book Feature Module. This will have the AddressBook component and an AddressBook service.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AddressBookComponent } from './addressBook.component'
import { AddressBookService } from './addressBook.service'
@NgModule({
imports: [ CommonModule ],
declarations: [ AddressBookComponent ],
exports: [ AddressBookComponent ],
providers: [ AddressBookService ]
})
export class AddressBookModule { }
AddressBook Service
import {Injectable} from '@angular/core'
@Injectable()
export class AddressBookService {
constructor(){
}
getContacts():string[] {
return [
"Alice ([email protected])",
"Bob ([email protected])",
"Chris ([email protected])"
];
}
}
AddressBook Component
import { Component } from '@angular/core'
import { AddressBookService } from './addressBook.service'
@Component({
selector: 'address-book',
template: `
<div>
<h2>Address Book</h2>
<div ngFor='let contact of contacts; let idx = index'>
<div>{{idx+1}} - {{contact}}</div>
</div>
</div>
`
})
export class AddressBookComponent implements OnInit{
contacts : string[];
constructor(private _service : AddressBookService){
}
ngOnInit(){
this.contacts = this._service.getContacts();
}
}
Note : Both in the MailBoxModule and AddressBookModule, we are not importing BrowserModule but we are importing CommonModule. The reason is that some essential services to launch and run a browser app is provided by BrowserModule. BrowserModule also re-exports CommonModule from @angular/common. We should not import BrowserModule in any other module. Feature modules and lazy-loaded modules should import CommonModule instead.