Angular2 Modules

Presented By Tom Acree

Columbus AngularJS Meetup Nov, 2016

What We Will Cover

  • Typescript ES6/ES2015 Modules
  • NgModule
  • NgModule Usage Patterns

Modules Overloaded

  • Angular NgModule and ES6 Modules are unrelated
  • The term is unfortunately overused

ES6 Modules

  • A formal way to encapsulate and organize groups of functionality in a bundled application
  • From the Typescript documentation: “In TypeScript, just as in ECMAScript 2015 (ES6), any file containing a top-level import or export is considered a module.”

ES2015 Module Details

File Driven

  • A file constitutes an importable module
  • No import/export is technically required
  • Files can have multiple import/exports
  • Files that are imported are more or less treated as a module

Always in Strict Mode

Top Level Scope is not Global Scope

  • Each module has its own scope
  • Global scope is available through the global variable
    • In a browser app this is the window object
  • this is undefined

May Import/Export Bindings to/from Other Modules

  • A module can be used for to simply combine other modules together and export all bindings

Export

  • Any Declaration can be Exported
  • In TypeScript the following is Exportable:
    • Variable
    • Function
    • Class
    • interface

Import

  • All imported bindings are const.  There references can't be reassigned.
    • imported primitives like numbers can't be imported and changed.
    • Values in an object reference can
  • Must be at the top level of the file, not inside {} scope
    • No conditional import
  • import is hoisted
  • import/export can be cyclic having recursive dependencies

Import/Export Examples

  • See sample project es6-modules branch

Typescript 2 typings Installation

  • typings is no longer needed, types are loaded from npm_modules @types/module-name
> npm install --save lodash
> npm install --save @types/lodash

# No need to update typings.d.ts, Typescript can read types from node_modules
# now you can do the following in your module files

// import lodash library
import * as _ from "lodash";

# See tsconfig.json typeRoots setting

NgModule Decorator

  • This decorator defines an Angular module
  • Metadata about your application or reusable components
    • Assembles many ES6 modules and components together
  • Unfortunately named
    • overloads the term module
    • "NgPackage" may have been a better name?

NgModule Metadata Interface

interface NgModule {
    imports : Array<Type<any>|ModuleWithProviders|any[]>
    declarations : Array<Type<any>|any[]>
    bootstrap : Array<Type<any>|any[]>
    providers : Provider[]
    
    exports : Array<Type<any>|any[]>
    
    entryComponents : Array<Type<any>|any[]>
    schemas : Array<SchemaMetadata|any[]>
    id : string
}

Decorator accepts a single object with properties that describe the module.

NgModule Usage Patterns

  • Root Module
  • Feature Module
  • Routing Module

Root Module

  • Required by every application
  • Provides key metadata for bootstrapping our application
  • Generally defines the following:
    • imports
    • declarations
    • bootstrap
    • providers

Example Root Module

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule
  ],

  declarations: [
    AppComponent
  ],

  bootstrap: [AppComponent],

  providers: []
})
export class AppModule { }

imports Property

  • Identifies other NgModules whose exports property contains other components needed by component templates in this module.
  • Only modules are imported here
@NgModule({
  imports: [
    BrowserModule,
    FormsModule
  ],
...
})
export class AppModule { }
  • BrowserModule exports CommonModule
    • It contains standard angular components such as NgIf and NgFor
  • FormsModule contains form functionality

declarations Property

  • Accept Array<any>
  • Generally declare Component,  Pipe, and Directive items implemented and used by this module.
  • Imported modules that have declarations in them are NOT automatically available to this module.
    • We'll discuss this when we look at the export property
@NgModule({
...
  declarations: [
    AppComponent
  ],
...
})
export class AppModule { }

bootstrap Property

  • Accept Array<any>
  • The presence of the bootstrap property identifies it as a root module
  • Identifies the Component to load
  • Indicates to the launcher which component is the point of entry
  • Even though it accepts an Array is generally a single component
@NgModule({
...
  bootstrap: [AppComponent],
...
})
export class AppModule { }

providers Property

  • Accept Array<Provider>
  • Identifies services or @Injectables that are available for dependency injection within declared Components
  • Adding a provider to a module makes the provider available to the whole application
    • Exception with lazy-loaded modules
  • Providers from imported modules are available for use as well
@NgModule({
...
  providers: [LoginService],
...
})
export class AppModule { }

Root Module Example

  • See root-module branch in sample project

Feature Modules

  • Feature Modules are intended to extend the application
  • Defined more by their intent that major differences from Root Modules
  • Differences
    • root modules are used to launch an app
    • feature modules extend an app
    • They export functionality that is used by other modules

NgModule export Property

  • Identifies Components that are made available to modules that import the current module
  • Include Component, Pipes, and Directives
  • Also includes modules
    • exporting a module means the importing module receives it as well

Example

  • See Example code simple-feature branch

Routing Module

  • Just like a feature module but isolates the routing concern
  • Does not concern itself with feature module declarations

forRoot and forChild

  • static methods on the RouterModule
  • Naming used by convention by developers, not part of Angular api

forRoot

forChild

  • Always call RouterModule.forChild in a child feature routing module
  • Only adds the routes to the route routing configuration
  • Does Not create new providers but rather uses the existing ones

Example

  • See routing-module branch

Lazy Loading a Routing Module

  • A lazy loaded routing module is one that is not loaded until the user loads the route
  • Completely decouples the feature from the main AppModule
  • Import Impact!!
    • When a route is lazily loaded, a new angular "context" and child injector for that route is created
      • This means that any provider declared in the lazy module is added to the new injector

Preventing Service Duplication using ModuleWithProviders

  • Use the forRoot convention to return a ModuleWithProviders instance
  • Remove the shared service from the providers array
  • Load it in the root module so that providers are added to the root injector
  • In lazy-loaded modules, import the module without the forRoot containing the providers

Shared Service Example

  • See shared-module branch in example app

NgModule Resources

Modules with Angular 2 and Typescript 2

By Tom Acree

Modules with Angular 2 and Typescript 2

These slides accompany the Nov, 2016 meetup for ng-columbus. This presentation discusses es2015 modules vs the NgModule concept from Angular 2.

  • 852