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
- Cannot opt out of this
- Strict mode used to help error-proof common JavaScript mistakes
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
- Used only by the root module
- Never call in a child/feature module
- Returns a ModuleWithProviders instance
- See Documentation: https://goo.gl/jy6RZI
- Includes any services the RouterModule provides
- See: https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#!#q-for-root
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
- When a route is lazily loaded, a new angular "context" and child injector for that route is created
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