© Venkata Keerti Kotaru 2020
V. K. KotaruAngular for Material Designhttps://doi.org/10.1007/978-1-4842-5434-9_3

3. Modules

Venkata Keerti Kotaru1 
(1)
Hyderabad, India
 

This chapter covers module systems in JavaScript and Angular. Modules are important for Angular code organization and the logical groupings of code. Modules also manage dependencies. An application has many files, classes, functions, and so forth. No code works in a silo or without integrating with other code units. A method in a class calls another method, which creates a dependency. A module system manages the dependency tree.

All modern JavaScript applications use a module system introduced in ES6 (also called ES2015). Angular applications use it, too; however, Angular also uses its own modules system. This chapter explains both modules.
  • The JavaScript module system is useful for grouping JavaScript functions, classes, constants, and so forth.

  • Angular modules are containers for Angular components, directives, services, and so forth. You can create a logical grouping of code units in a module and retrieve them using Angular’s dependency injection. The Angular module system is used in addition to JavaScript modules.

Figure 3-1 is a visual depiction of the modules.

Note

JavaScript has its own module system from ECMA Script 2015 (ES6). Earlier, JavaScript used custom libraries like RequireJS to implement modules. During the course of this book, however, we use TypeScript. It shares the concept of modules introduced in ES6. For the purposes of this chapter, we will call them JavaScript modules.

../images/475625_1_En_3_Chapter/475625_1_En_3_Fig1_HTML.jpg
Figure 3-1

Module system

JavaScript Modules

JavaScript modules create a logical grouping of JavaScript/TypeScript classes, functions, constants, and so forth. Listing 3-1 is from the Superheroes sample application. It imports classes from a few modules.
-- app.module.ts --
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
Listing 3-1

JavaScript Imports from a Module

Note

@angular prefixes Angular code components, directives, services, and so forth. The prefix matches with Angular npm monorepo. For example, you may install an Angular library CDK with the command shown in Listing 3-2.

npm install @angular/cdk
Listing 3-2

Install from npm monorepo

or
yarn add @angular/cdk
The app.module.ts file exports a class (see Listing 3-3).
-- app.module.ts continued --
@NgModule({
​// Removed code for brevity.
})
export class AppModule { }
Listing 3-3

JavaScript Export

The ts file (TypeScript file) acts as a module. You may define more than one class or function in a file. Be sure to export the class or the function so that it is available outside the module.

This information is sufficient for understanding the Angular concepts covered in this book. To learn more about JavaScript modules, refer to the “More About JavaScript Modules” section later in the chapter.

Angular Modules

Angular modules serve a purpose different from JavaScript modules. They act as a container for Angular code. Angular modules create logical groupings of components, directives, pipes, services, and so forth. A typical Angular application includes many modules.

Continuing with the app.module.ts, Listing 3-3 creates an Angular module with @NgModule decorator, which contains metadata for creating the Angular module. The AppModule in the sample application (created by Angular CLI) is the root module of the entire application. AppModule is a class (see Listing 3-4).
--- app.module.ts ----
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
 declarations: [
   AppComponent
 ],
 imports: [BrowserModule],
 bootstrap: [AppComponent]
})
export class AppModule { }
Listing 3-4

Root Module app.module.ts

The JavaScript module imports BrowserModule and NgModule at the beginning of the file.
  • NgModule is a decorator needed to create a new module in the Angular application. You use the decorator annotated on top of the AppModule module class . It captures the metadata for the module. A decorator is a new feature in both JavaScript and TypeScript. In JavaScript, it was a “proposal” feature at the time of authoring this content.

  • BrowserModule is a required Angular infrastructure module available with the Angular library. It is required for an Angular application running on a browser like Google Chrome or Firefox. Angular applications can also run outside the context of a client browser on a Node.js server application. These applications do not have to use BrowserModule.

You also import the root component for the entire application, which is typically called AppComponent. This the first component created by Angular CLI.

The ngModule decorator has the following metadata fields.
  • declarations : An array that declares components and other Angular code to be part of the module (see Listing 3-5), AppComponent is declared on the root module. It is the only component created so far in the application. As we create additional components during the course of this book, we add them to declarations. Angular CLI automatically adds declarations when creating a new component. Listing 3-5 shows how to create a new component with Angular CLI.

  • bootstrap : Specify the root component of the Angular application here. Only one module can use the bootstrap field for an application. AppModule is the root module when we create the application; it bootstraps with the first component, AppComponent.

  • imports : As mentioned, an Angular application includes many Angular modules. To use features from other modules, import them to the Angular module by including the module class reference in the imports array. For now, we import the BrowserModule platform module.

For complete list of metadata fields, see the “ngModule Decorator Complete List of Fields” section.

Note

The decorator pattern augments a class with additional features, without modifying the class definition. In this case, the additional features include metadata fields and functions that the module class will carry.

To generate a new component using Angular CLI, run the command in Listing 3-5.
ng generate component my-sample-component
Listing 3-5

Create a Component with Angular CLI

An Approach to Modules

Modules are containers of Angular code. They are a logical group of classes, functions, components, directives, and so forth. While there is no one approach to logical groupings, in the superheroes code sample, we group all Material Design components and other code units in a module (see Figure 3-2).
../images/475625_1_En_3_Chapter/475625_1_En_3_Fig2_HTML.jpg
Figure 3-2

Angular modules and dependencies

Figure 3-2 describes the dependencies between Angular modules. AppModule is the root module. It depends on Angular platform modules like BrowserModule. In other words, AppModule imports BrowserModule and other platform-level modules. Notice the dependency with gray boxes in Figure 3-2.

Let’s create a new module: SuperheroesMaterialDesignModule. In the Superheroes sample application, consider grouping all Material Design (Angular Material) components into this module. In the code samples so far, you have seen a card and a toolbar. For these components to function, we need to import MatCardModule and MatToolbarModule. As we work with more Angular Material components, we import more modules.

Briefly, AppModule depends on SuperheroesMaterialDesignModule and Angular platform modules. The SuperheroesMaterialDesignModule, in turn, depends on more Angular Material modules. Notice the dark boxes in Figure 3-2.

Create an Angular Module

Use the Angular CLI command in Listing 3-6 to create a new module.
ng generate module superheroes-material-design
Listing 3-6

Create an Angular Module

If you do not use Angular CLI, create a module TypeScript class (preferably in a separate file and folder) and decorate it with @ngModule.

Angular CLI creates the module file in a new folder: app/superheroes-material-design. The file name matches the folder name: superheroes-material-design.module.ts. The module class is named in pascal case: SuperheroesMaterialDesignModule.

Notice the “Mat” prefix on all Angular Material modules, components, and so forth. Import the Mat∗ (Angular Material) modules to the newly created SuperheroesMaterialDesignModule (see Listing 3-7).
-- superheroes-material-design.module.ts --
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatCardModule } from '@angular/material/card';
@NgModule({
 imports: [
   BrowserAnimationsModule,
   MatCardModule,
   MatToolbarModule
 ]
, // ** removed other metadata objects for brevity.
// ** this module definition is not complete. We will create modules and reference them.
})
export class SuperheroesMaterialDesignModule { }
Listing 3-7

Superheroes Material Design Module

Import MatToolbarModule and MatCardModule from the Angular Material library, which are @angular/material/toolbar and @angular/material/card, respectively. The imports array with the Mat∗ modules allow all exported Angular code from the Mat∗ modules to be used in the newly created module. You can reference and use the components, services, and so forth in SuperheroesMaterialDesignModule’s components and services. Creating and using components and services are discussed in other chapters in the book.

Note

We are also importing BrowserAnimationModule because Angular Material uses animations. If you need to skip animations, you should import NoopAnimationsModule to avoid errors due to a missing animation API when using Material Design components.

Pretend that the components that render a superheroes profile on a card and toolbar are ready and available in the application. Include them in SuperheroesMaterialDesignModule by importing the component classes and declaring them on @ngModule (see Listing 3-8).
Import { SuperheroProfileComponent } from "./superhero-profile/superhero-profile.component";
Import { SuperheroToolbarComponent } from "./superhero-profile/superhero-toolbar.component";
@NgModule({
 declarations: [
   SuperheroProfileComponent,
   SuperheroToolbarComponent
 ],
 imports: [
   BrowserAnimationsModule,
   MatCardModule,
   MatToolbarModule
 ],
 exports: [
   SuperheroProfileComponent,
   SuperheroToolbarComponent
 ]
})
export class SuperheroesMaterialDesignModule { }
Listing 3-8

Import and Export Profile and Toolbar Components

Including the SuperheroProfileComponent and SuperheroToolbarComponent components in the declarations array makes them part of the module.

For these components to be accessible outside the SuperheroesMaterialDesignModule module, you need to export them as well. Notice the exports array in the @ngModule metadata.

Let’s now import the new SuperheroesMaterialDesignModule to AppModule so that the exported Angular code from the module is usable in the root module and the rest of the application (see Listing 3-9). Review Figure 3-2 again to better understand the module dependencies.
-- app.module.ts --
import { SuperheroesMaterialDesignModule } from './superheroes-material-design/superheroes-material-design.module';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
 declarations: [
   // ** removed other metadata objects for brevity.
 ],
 imports: [
   BrowserModule,
   AppRoutingModule,
   SuperheroesMaterialDesignModule
 ],
})
export class AppModule { }
Listing 3-9

App Module Importing SuperheroesMaterialDesignModule

NgModule Decorator Complete List of Fields

The following is a list of the metadata fields used when creating a module.

Declarations

Declarations are the Angular components, directives, and pipes that belong to a module. We do not include provider services here. In Listing 3-9, we declared two components: SuperheroesProfileComponent and SuperheroesToolbarComponent.

Imports

Imports provide a list of modules in an array so that the given module has access to them. In the sample, we included MatCardModule. It contains a mat-card component. Now, the mat-card component is available to SuperheroesMaterialDesignModule components.

Exports

Not everything defined in an Angular module needs to be publicly available outside the module. The exports array provides a list of the components, pipes, or directives that are available to a module importing the current one.

Providers

Providers are a list of Angular services in an array. An angular service is a reusable class that is injectable into a component or another service. A separate chapter in the book elaborates creating and using services in Angular; however, for now, understand that a service needs to be provided or instantiated. It is done at the application level, module level, or at a component level.

A service provided at the module level instantiates it for the entire module. Hence, the state of the service or the values in the service is retained across multiple components in the module. It is like maintaining data at a global or module level.

Chapter 7 explains more about services.

Bootstrap

In Listing 3-10, notice app.module.ts. The AppModule, which is the root module, or the first main module of the application, bootstraps with AppComponent. Only one module in an application can use the bootstrap field.
@NgModule({
 declarations: [
   AppComponent
 ],
 imports: [
   BrowserModule,
   AppRoutingModule,
   SuperheroesMaterialDesignModule
 ],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }
Listing 3-10

App Module Bootstraps AppComponent

More About JavaScript Modules

Modules are included in JavaScript and TypeScript files. Each file can have exactly one module. Each file can import and export multiple items such as classes, objects, functions, and constants.

The Primary Ways to Import and Export Code

To export an item, use the export keyword. Each file can have one default export, which can export multiple other items. Listing 3-11 exports an Array object and two other functions. The `superheroes` array is exported as the default.
const superheroes: SuperHero[] = [
    {
        name: "batman",
        creators: ["Bob Kane", "Bill Finger"],
        firstAppearance: "Year 1939",
        livesIn: "Gotham City",
    },
    {
        name: "Chhota Bheem",
        creators: [
            "Raj Viswanadha",
            "Arun Shendurnikar",
            "Nidhi Anand”
        ],
        firstAppearance: "Year 2008",
        livesIn: "India",
    },
];
export default superheroes;
function findSuperhero(name: string): SuperHero[] {
    return superheroes.find(x => x.name === name);
}
export function getSuperheroLocation(name: string): string {
    return findSuperhero(name).livesIn;
}
export function getSuperheroCreators(name: string): string {
    return findSuperhero(name).creators;
}
Listing 3-11

Export JavaScript Modules

Notice that we did not export the findSuperhero function. Hence, we cannot access it outside the module or file. It is private to the module. The other functions are APIs exposed for other modules to use.

In another file, import and use the functions and the objects. In Listing 3-12, notice that the syntax, the default export, is not included in parentheses.
import  superheroes, {getSuperheroCreators, getSuperheroLocation} from './superhero';
Listing 3-12

Import JS Modules

In Listing 3-11 and Listing 3-12, getSuperheroCreators and getSuperheroLocation are called named exports. There can be multiple named exports. The file importing the JavaScript code (functions, in this case) identifies the function with its name. That means it cannot be an anonymous function.

There is a single default export from a module, however. Hence, it can be anonymous. We can rewrite Listing 3-13 to default export an anonymous array object.
export default [
   {
       name: "batman",
       creators: ["Bob Kane", "Bill Finger"],
       firstAppearance: "Year 1939",
       livesIn: "Gotham City",
   },
   {
       name: "Chhota Bheem",
       creators: [
           "Raj Viswanadha",
           "Arun Shendurnikar",
           "Nidhi Anand"],
       firstAppearance: "Year 2008",
       livesIn: "India",
   },
];
Listing 3-13

Anonymous Default Export of an Array Object

We import this code with Listing 3-14. The name of the object can by anything.
import aCustomObjectName from './superhero';
Listing 3-14

Import an Anonymous Object

It also holds well for anonymous functions (see Listing 3-15).
export default function (name: string): string {
   // function definition
}
Listing 3-15

Export an Anonymous Function

Import All

To import all functions, constants, and classes from a module, use the following syntax.
import * as heroApi from './superhero'
It creates a variable, heroApi, in the importing TypeScript file. Access the named imports with the function or constant name.
heroApi.getSuperheroCreators("batman")
Access the default export with the default keyword.
heroApi.default
You may rename the default import with the following syntax. Notice that getSuperheroCreators was renamed to renamedSuperheroCreators with the “as” keyword.
import  superheroes, {getSuperheroCreators as renamedSuperheroCreators, getSuperheroLocation} from './superhero'
Access it in the class or function with the custom name.
renamedSuperheroCreators("batman")

Conclusion

It is important to understand module systems while developing complex applications with Angular, JavaScript, or TypeScript. In this chapter, we began by introducing the ES6/ES2015 module system. The chapter described the basics of importing and exporting JavaScript and TypeScript classes, functions, constants, and so forth.

Next, the chapter described Angular modules. It explained how to create an Angular module by using the NgModule decorator. It covered the usage of fields within the NgModule decorator. These fields and their values act as metadata for the Angular module.

The chapter described logical groupings and code organization with the Superheroes sample application. At the end, the chapter elaborated on ES6 module syntaxes and usage.

References

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.95.38