Angular Modules

Go back to Tutorial

Angular defines the NgModule, which differs from and complements the JavaScript (ES2015) module. An NgModule declares a compilation context for a set of components that is dedicated to an application domain, a workflow, or a closely related set of capabilities. An NgModule can associate its components with related code, such as services, to form functional units.

Every Angular app has a root module, conventionally named AppModule, which provides the bootstrap mechanism that launches the application. An app typically contains many functional modules.

Like JavaScript modules, NgModules can import functionality from other NgModules, and allow their own functionality to be exported and used by other NgModules. For example, to use the router service in your app, you import the Router NgModule.

Organizing your code into distinct functional modules helps in managing development of complex applications, and in designing for reusability. In addition, this technique lets you take advantage of lazy-loading—that is, loading modules on demand—in order to minimize the amount of code that needs to be loaded at startup.

NgModule Basics

NgModules configure the injector and the compiler and help organize related things together. An NgModule is a class marked by the @NgModule decorator. @NgModule takes a metadata object that describes how to compile a component’s template and how to create an injector at runtime. It identifies the module’s own components, directives, and pipes, making some of them public, through the exports property, so that external components can use them. @NgModule can also add service providers to the application dependency injectors.

Angular Modularity – Modules are a great way to organize an application and extend it with capabilities from external libraries.

Angular libraries are NgModules, such as FormsModule, HttpClientModule, and RouterModule. Many third-party libraries are available as NgModules such as Material Design, Ionic, and AngularFire2.

NgModules consolidate components, directives, and pipes into cohesive blocks of functionality, each focused on a feature area, application business domain, workflow, or common collection of utilities.

Modules can also add services to the application. Such services might be internally developed, like something you’d develop yourself or come from outside sources, such as the Angular router and HTTP client.

Modules can be loaded eagerly when the application starts or lazy loaded asynchronously by the router.

NgModule metadata does the following:

  • Declares which components, directives, and pipes belong to the module.
  • Makes some of those components, directives, and pipes public so that other module’s component templates can use them.
  • Imports other modules with the components, directives, and pipes that components in the current module need.
  • Provides services that the other application components can use.

Every Angular app has at least one module, the root module. You bootstrap that module to launch the application.

The root module is all you need in a simple application with a few components. As the app grows, you refactor the root module into feature modules that represent collections of related functionality. You then import these modules into the root module.

The basic NgModule – The CLI generates the following basic app module when creating a new app.

src/app/app.module.ts

// imports

import { BrowserModule } from ‘@angular/platform-browser’;

import { NgModule } from ‘@angular/core’;

import { FormsModule } from ‘@angular/forms’;

import { HttpModule } from ‘@angular/http’;

import { AppComponent } from ‘./app.component’;

import { ItemDirective } from ‘./item.directive’;

// @NgModule decorator with its metadata

@NgModule({

declarations: [

AppComponent,

ItemDirective

],

imports: [

BrowserModule,

FormsModule,

HttpModule

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

At the top are the import statements. The next section is where you configure the @NgModule by stating what components and directives belong to it (declarations) as well as which other modules it uses (imports).

Frequently Used Modules – An Angular app needs at least one module that serves as the root module. As you add features to your app, you can add them in modules. The following are frequently used Angular modules with examples of some of the things they contain:

NgModule Import it from Why you use it
BrowserModule @angular/platform-browser When you want to run your app in a browser
CommonModule @angular/common When you want to use NgIf, NgFor
FormsModule @angular/forms When you build template driven forms (includes NgModel)
ReactiveFormsModule @angular/forms When building reactive forms
RouterModule @angular/router For Routing and when you want to use RouterLink,.forRoot(), and .forChild()
HttpClientModule @angular/common/http When you to talk to a server

 

Importing modules – When you use these Angular modules, import them in AppModule, or your feature module as appropriate, and list them in the @NgModule imports array. For example, in the basic app generated by the CLI, BrowserModule is the first import at the top of the AppModule, app.module.ts.

/* import modules so that AppModule can access them */

import { BrowserModule } from ‘@angular/platform-browser’;

import { NgModule } from ‘@angular/core’;

import { AppComponent } from ‘./app.component’;

@NgModule({

declarations: [

AppComponent

],

imports: [ /* add modules here so Angular knows to use them */

BrowserModule,

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

The imports at the top of the array are JavaScript import statements while the imports array within @NgModule is Angular specific.

Bootstrapping

An NgModule describes how the application parts fit together. Every application has at least one Angular module, the root module that you bootstrap to launch the application. By convention, it is usually called AppModule.

If you use the CLI to generate an app, the default AppModule is as follows:

/* JavaScript imports */

import { BrowserModule } from ‘@angular/platform-browser’;

import { NgModule } from ‘@angular/core’;

import { FormsModule } from ‘@angular/forms’;

import { HttpModule } from ‘@angular/http’;

import { AppComponent } from ‘./app.component’;

/* the AppModule class with the @NgModule decorator */

@NgModule({

declarations: [

AppComponent

],

imports: [

BrowserModule,

FormsModule,

HttpModule

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

After the import statements is a class with the @NgModule decorator.

The @NgModule decorator identifies AppModule as an NgModule class. @NgModule takes a metadata object that tells Angular how to compile and launch the application.

  • declarations—this application’s lone component.
  • imports—import BrowserModule to have browser specific services such as DOM rendering, sanitization, and location.
  • providers—the service providers.
  • bootstrap—the root component that Angular creates and inserts into the index.html host web page.

The default CLI application only has one component, AppComponent, so it is in both the declarations and the bootstrap arrays.

The declarations array – The module’s declarations array tells Angular which components belong to that module. As you create more components, add them to declarations.

You must declare every component in exactly one NgModule class. If you use a component without declaring it, Angular returns an error message.

The declarations array only takes declarables. Declarables are components, directives and pipes. All of a module’s declarables must be in the declarations array. Declarables must belong to exactly one module. The compiler emits an error if you try to declare the same class in more than one module.

These declared classes are visible within the module but invisible to components in a different module unless they are exported from this module and the other module imports this one.

An example of what goes into a declarations array follows:

declarations: [

YourComponent,

YourPipe,

YourDirective

],

A declarable can only belong to one module, so only declare it in one @NgModule. When you need it elsewhere, import the module that has the declarable you need in it.

Only @NgModule references go in the imports array.

Using directives with @NgModule – Use the declarations array for directives. To use a directive, component, or pipe in a module, you must do a few things:

  • Export it from the file where you wrote it.
  • Import it into the appropriate module.
  • Declare it in the @NgModule declarations array.

The imports array – The module’s imports array appears exclusively in the @NgModule metadata object. It tells Angular about other NgModules that this particular module needs to function properly.

This list of modules are those that export components, directives, or pipes that the component templates in this module reference. In this case, the component is AppComponent, which references components, directives, or pipes in BrowserModule, FormsModule, or HttpModule. A component template can reference another component, directive, or pipe when the referenced class is declared in this module or the class was imported from another module.

You don’t have any services to provide yet. But you will create some before long and you may chose to provide many of them here.

The providers array – The providers array is where you list the services the app needs. When you list services here, they are available app-wide. You can scope them when using feature modules and lazy loading.

 

The bootstrap array – The application launches by bootstrapping the root AppModule, which is also referred to as an entryComponent. Among other things, the bootstrapping process creates the component(s) listed in the bootstrap array and inserts each one into the browser DOM.

Each bootstrapped component is the base of its own tree of components. Inserting a bootstrapped component usually triggers a cascade of component creations that fill out that tree.

While you can put more than one component tree on a host web page, most applications have only one component tree and bootstrap a single root component. This one root component is usually called AppComponent and is in the root module’s bootstrap array.

Bootstrap in main.ts – There are many ways to bootstrap an application. The variations depend upon how you want to compile the application and where you want to run it.

In the beginning, you will compile the application dynamically with the Just-in-Time (JIT) compiler and you’ll run it in a browser. You can learn about other options later.

The recommended place to bootstrap a JIT-compiled browser application is in a separate file in the src folder named src/main.ts

src/main.ts

import { platformBrowserDynamic } from ‘@angular/platform-browser-dynamic’;

import { AppModule }              from ‘./app/app.module’;

platformBrowserDynamic().bootstrapModule(AppModule);

This code creates a browser platform for dynamic (JIT) compilation and bootstraps the AppModule described above.

The bootstrapping process sets up the execution environment, digs the root AppComponent out of the module’s bootstrap array, creates an instance of the component and inserts it within the element tag identified by the component’s selector.

The AppComponent selector — here and in most documentation samples — is my-app so Angular looks for a <my-app> tag in the index.html like this one …

setup/src/index.html

<my-app><!– content managed by Angular –></my-app>

… and displays the AppComponent there.

This file is very stable. Once you’ve set it up, you may never change it again.

Angular Do-Bootstrap – DoBootstrap – It is an interface and hook for manual bootstrapping of the application instead of using bootstrap array in @NgModule annotation. Reference to the current application is provided as a parameter.

interface DoBootstrap {

ngDoBootstrap(appRef: ApplicationRef): void

}

It has a method – ngDoBootstrap() and usage is as

ngDoBootstrap(appRef: ApplicationRef): void

Example

class AppModule implements DoBootstrap {

ngDoBootstrap(appRef: ApplicationRef) {

appRef.bootstrap(AppComponent); // Or some other component

}

}

Components

Every Angular application has at least one component, the root component that connects a component hierarchy with the page DOM. Each component defines a class that contains application data and logic, and is associated with an HTML template that defines a view to be displayed in a target environment.

The @Component decorator identifies the class immediately below it as a component, and provides the template and related component-specific metadata.

Decorators are functions that modify JavaScript classes. Angular defines a number of such decorators that attach specific kinds of metadata to classes, so that it knows what those classes mean and how they should work.

NgModule Metadata

An NgModule is defined as a class decorated with @NgModule. The @NgModule decorator is a function that takes a single metadata object, whose properties describe the module. The most important properties are as follows.

  • declarations—The components, directives, and pipes that belong to this NgModule.
  • exports—The subset of declarations that should be visible and usable in the component templates of other NgModules.
  • imports—Other modules whose exported classes are needed by component templates declared in this NgModule.
  • providers—Creators of services that this NgModule contributes to the global collection of services; they become accessible in all parts of the app. (You can also specify providers at the component level, which is often preferred.)
  • bootstrap—The main application view, called the root component, which hosts all other app views. Only the root NgModule should set this bootstrap property.

Here’s a simple root NgModule definition:

src/app/app.module.ts

import { NgModule }      from ‘@angular/core’;

import { BrowserModule } from ‘@angular/platform-browser’;

@NgModule({

imports:      [ BrowserModule ],

providers:    [ Logger ],

declarations: [ AppComponent ],

exports:      [ AppComponent ],

bootstrap:    [ AppComponent ]

})

export class AppModule { }

The export of AppComponent is just to show how to export; it isn’t actually necessary in this example. A root NgModule has no reason to export anything because other modules don’t need to import the root NgModule.

NgModules and Components

NgModules provide a compilation context for their components. A root NgModule always has a root component that is created during bootstrap, but any NgModule can include any number of additional components, which can be loaded through the router or created through the template. The components that belong to an NgModule share a compilation context.

A component and its template together define a view. A component can contain a view hierarchy, which allows you to define arbitrarily complex areas of the screen that can be created, modified, and destroyed as a unit. A view hierarchy can mix views defined in components that belong to different NgModules. This is often the case, especially for UI libraries.

When you create a component, it is associated directly with a single view, called the host view. The host view can be the root of a view hierarchy, which can contain embedded views, which are in turn the host views of other components. Those components can be in the same NgModule, or can be imported from other NgModules. Views in the tree can be nested to any depth.

The hierarchical structure of views is a key factor in the way Angular detects and responds to changes in the DOM and app data.

NgModules – NgModules help organize an application into cohesive blocks of functionality. An NgModule is a class adorned with the @NgModule decorator function. @NgModule takes a metadata object that tells Angular how to compile and run module code. It identifies the module’s own components, directives, and pipes, making some of them public so external components can use them. @NgModule may add service providers to the application dependency injectors. And there are many more options covered here.

Many Angular libraries are modules (such as FormsModule, HttpModule, and RouterModule). Many third-party libraries are available as NgModules (such as Material Design, Ionic, AngularFire2).

NgModules consolidate components, directives, and pipes into cohesive blocks of functionality, each focused on a feature area, application business domain, workflow, or common collection of utilities.

Modules can also add services to the application. Such services might be internally developed, such as the application logger. Services can come from outside sources, such as the Angular router and Http client.

Modules can be loaded eagerly when the application starts. They can also be lazy loaded asynchronously by the router.

An NgModule is a class decorated with @NgModule metadata. The metadata do the following:

  • Declare which components, directives, and pipes belong to the module.
  • Make some of those classes public so that other component templates can use them.
  • Import other modules with the components, directives, and pipes needed by the components in this module.
  • Provide services at the application level that any application component can use.

Every Angular app has at least one module class, the root module. You bootstrap that module to launch the application.

The root module is all you need in a simple application with a few components. As the app grows, you refactor the root module into feature modules that represent collections of related functionality. You then import these modules into the root module.

The root AppModule – Every Angular app has a root module class. By convention, the root module class is called AppModule and it exists in a file named app.module.ts.

The AppModule from the QuickStart seed on the Setup page is as minimal as possible:

src/app/app.module.ts (minimal)

import { NgModule }      from ‘@angular/core’;

import { BrowserModule } from ‘@angular/platform-browser’;

import { AppComponent }  from ‘./app.component’;

@NgModule({

imports:      [ BrowserModule ],

declarations: [ AppComponent ],

bootstrap:    [ AppComponent ]

})

export class AppModule { }

The @NgModule decorator defines the metadata for the module. This page takes an intuitive approach to understanding the metadata and fills in details as it progresses.

The metadata imports a single helper module, BrowserModule, which every browser app must import.

BrowserModule registers critical application service providers. It also includes common directives like NgIf and NgFor, which become immediately visible and usable in any of this module’s component templates.

The declarations list identifies the application’s only component, the root component, the top of the app’s rather bare component tree. The example AppComponent simply displays a data-bound title:

src/app/app.component.ts (minimal)

import { Component } from ‘@angular/core’;

@Component({

selector: ‘my-app’,

template: ‘<h1>{{title}}</h1>’,

})

export class AppComponent {

title = ‘Minimal NgModule’;

}

Lastly, the @NgModule.bootstrap property identifies this AppComponent as the bootstrap component. When Angular launches the app, it places the HTML rendering of AppComponent in the DOM, inside the <my-app> element tags of the index.html.

Providers in Angular

A provider is an instruction to the DI system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide.

Providing a service – If you already have a CLI generated app, create a service using the following CLI command in the root project directory. Replace User with the name of your service.

ng generate service User

This command creates the following UserService skeleton:

src/app/user.service.0.ts

import { Injectable } from ‘@angular/core’;

@Injectable({

providedIn: ‘root’,

})

export class UserService {

}

You can now inject UserService anywhere in your application.

The service itself is a class that the CLI generated and that’s decorated with @Injectable. By default, this decorator is configured with a providedIn property, which creates a provider for the service. In this case, providedIn: ‘root’ specifies that the service should be provided in the root injector.

Provider scope – When you add a service provider to the root application injector, it’s available throughout the app. Additionally, these providers are also available to all the classes in the app as long they have the lookup token.

You should always provide your service in the root injector unless there is a case where you want the service to be available only if the consumer imports a particular @NgModule.

providedIn and NgModules – It’s also possible to specify that a service should be provided in a particular @NgModule. For example, if you don’t want UserService to be available to applications unless they import a UserModule you’ve created, you can specify that the service should be provided in the module:

src/app/user.service.1.ts

import { Injectable } from ‘@angular/core’;

import { UserModule } from ‘./user.module’;

@Injectable({

providedIn: UserModule,

})

export class UserService {

}

The example above shows the preferred way to provide a service in a module. This method is preferred because it enables tree-shaking of the service if nothing injects it. If it’s not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module:

src/app/user.module.ts

import { NgModule } from ‘@angular/core’;

import { UserService } from ‘./user.service’;

@NgModule({

providers: [UserService],

})

export class UserModule {

}

Singleton Services

There are two ways to make a service a singleton in Angular:

  • Declare that the service should be provided in the application root.
  • Include the service in the AppModule or in a module that is only imported by the AppModule.

Beginning with Angular 7.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting providedIn to root on the service’s @Injectable decorator:

src/app/user.service.0.ts

import { Injectable } from ‘@angular/core’;

@Injectable({

providedIn: ‘root’,

})

export class UserService {

}

NgModule API

At a high level, NgModules are a way to organize Angular apps and they accomplish this through the metadata in the @NgModule decorator. The metadata falls into three categories:

  • Static: Compiler configuration which tells the compiler about directive selectors and where in templates the directives should be applied through selector matching. This is configured via the declarations array.
  • Runtime: Injector configuration via the providers array.
  • Composability/Grouping: Bringing NgModules together and making them available via the imports and exports arrays.

@NgModule({

// Static, that is compiler configuration

declarations: [], // Configure the selectors

entryComponents: [], // Generate the host factory

// Runtime, or injector configuration

providers: [], // Runtime injector configuration

// Composability / Grouping

imports: [], // composing NgModules together

exports: [] // making NgModules available to other parts of the app

})

@NgModule metadata – The following table summarizes the @NgModule metadata properties.

Property Description
declarations A list of declarable classes, (components, directives, and pipes) that belong to this module.

ü  When compiling a template, you need to determine a set of selectors which should be used for triggering their corresponding directives.

ü  The template is compiled within the context of an NgModule—the NgModule within which the template’s component is declared—which determines the set of selectors using the following rules:

ü  All selectors of directives listed in `declarations`.

ü  All selectors of directives exported from imported NgModules.

Components, directives, and pipes must belong to exactly one module. The compiler emits an error if you try to declare the same class in more than one module.

Don’t re-declare a class imported from another module.

providers A list of dependency-injection providers.

Angular registers these providers with the NgModule’s injector. If it is the NgModule used for bootstrapping then it is the root injector.

These services become available for injection into any component, directive, pipe or service which is a child of this injector.

A lazy-loaded module has its own injector which is typically a child of the application root injector.

Lazy-loaded services are scoped to the lazy module’s injector. If a lazy-loaded module also provides the UserService, any component created within that module’s context (such as by router navigation) gets the local instance of the service, not the instance in the root application injector.

Components in external modules continue to receive the instance provided by their injectors.

imports A list of modules which should be folded into this module. Folded means it is as if all the imported NgModule’s exported properties were declared here.

Specifically, it is as if the list of modules whose exported components, directives, or pipes are referenced by the component templates were declared in this module.

A component template can reference another component, directive, or pipe when the reference is declared in this module or if the imported module has exported it. For example, a component can use the NgIf and NgFor directives only if the module has imported the Angular CommonModule (perhaps indirectly by importing BrowserModule).

You can import many standard directives from the CommonModule but some familiar directives belong to other modules. For example, you can use [(ngModel)] only after importing the Angular FormsModule.

exports A list of declarations—component, directive, and pipe classes—that an importing module can use.

Exported declarations are the module’s public API. A component in another module can use this module’s UserComponent if it imports this module and this module exports UserComponent.

Declarations are private by default. If this module does not export UserComponent, then only the components within this module can use UserComponent.

Importing a module does not automatically re-export the imported module’s imports. Module ‘B’ can’t use ngIf just because it imported module ‘A’ which imported CommonModule. Module ‘B’ must import CommonModule itself.

A module can list another module among its exports, in which case all of that module’s public components, directives, and pipes are exported.

Re-export makes module transitivity explicit. If Module ‘A’ re-exports CommonModule and Module ‘B’ imports Module ‘A’, Module ‘B’ components can use ngIf even though ‘B’ itself didn’t import CommonModule.

bootstrap A list of components that are automatically bootstrapped.

Usually there’s only one component in this list, the root component of the application.

Angular can launch with multiple bootstrap components, each with its own location in the host web page.

A bootstrap component is automatically added to entryComponents.

entryComponents A list of components that can be dynamically loaded into the view.

By default, an Angular app always has at least one entry component, the root component, AppComponent. Its purpose is to serve as a point of entry into the app, that is, you bootstrap it to launch the app.

Routed components are also entry components because they need to be loaded dynamically. The router creates them and drops them into the DOM near a <router-outlet>.

While the bootstrapped and routed components are entry components, you don’t have to add them to a module’s entryComponents list, as they are added implicitly.

Angular automatically adds components in the module’s bootstrap and route definitions into the entryComponents list.

That leaves only components bootstrapped using one of the imperative techniques, such as ViewComponentRef.createComponent() as undiscoverable.

Dynamic component loading is not common in most apps beyond the router. If you need to dynamically load components, you must add these components to the entryComponents list yourself.

Angular Libraries

Angular ships as a collection of JavaScript modules. You can think of them as library modules. Each Angular library name begins with the @angular prefix. Install them with the npm package manager and import parts of them with JavaScript import statements.

For example, import Angular’s Component decorator from the @angular/core library like this:

import { Component } from ‘@angular/core’;

You also import NgModules from Angular libraries using JavaScript import statements:

import { BrowserModule } from ‘@angular/platform-browser’;

In the example of the simple root module above, the application module needs material from within the BrowserModule. To access that material, add it to the @NgModule metadata imports like this.

imports:      [ BrowserModule ],

In this way you’re using both the Angular and JavaScript module systems together. Although it’s easy to confuse the two systems, which share the common vocabulary of “imports” and “exports”, you will become familiar with the different contexts in which they are used.

Go back to Tutorial

Share this post
[social_warfare]
Angular Dependency Injection
Angular Directives

Get industry recognized certification – Contact us

keyboard_arrow_up