understanding the App.Module
import tells Typescript what files to use
WebPack goes through the imports to bundle the app
Angular modules define how our app looks to Angular
in NgModule declaration imports property is an array of modules
when a module is imported everything the module exports is imported
in app-routing module the NgModule imports the RouterModule and applies the Route
array then the module exports the configured RouterModule
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
...
const appRoutes: Routes = [...];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
importing modules avoids the need to explicitly import the needed types individually
modules are bundles of functionality
Top
Index
understanding feature modules
custom module built for an app
in course project all recipe-related components could be in a features module
Top
Index
registering routes in a feature module
in recipes folder add recipes-routing.module
cut recipe-related paths from app-routing.module and paste them into the new module
import the RouterModule and use the forChild method to load the recipeRoutes array
and export the RouterModule
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
...
const recipesRoutes: Routes = [
{
path: 'recipes', component: RecipesComponent, children: [
{ path: '', component: RecipeStartComponent },
{ path: 'new', component: RecipeEditComponent, canActivate: [AuthGuard] },
// paths without dynamic IDs must be first
{ path: ':id', component: RecipeDetailComponent },
{ path: ':id/edit', component: RecipeEditComponent, canActivate: [AuthGuard] },
]
},
];
@NgModule({
imports: [RouterModule.forChild(recipesRoutes)],
exports: [RouterModule]
})
export class RecipesRoutingModule { }
in the recipes.module import the new module and add it to the NgModule's imports
property
...
import { RecipesRoutingModule } from './recipes-routing.module';
@NgModule({
declarations: [
...
],
imports: [
...,
RecipesRoutingModule
],
})
export class RecipesModule { }
Top
Index
understanding shared modules
the DropdownDirective is needed by both the app component and the feature module
put DropdownDirective into a shared module
add shared.module.ts in shared folder
typically only one shared module in an app
Top
Index
the module exports both the DropdownDirective and the CommonModule
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DropdownDirective } from './dropdown.directive';
@NgModule({
declarations: [
DropdownDirective
],
imports: [
CommonModule
],
exports: [
CommonModule,
DropdownDirective
]
})
export class SharedModule { }
in app.module remove the DropdownDirective import and declaration and import the
shared module
...
// import { DropdownDirective } from './shared/dropdown.directive';
import { SharedModule } from './shared/shared.module';
...
@NgModule({
declarations: [
...
// DropdownDirective,
SignInComponent,
SignUpComponent
],
imports: [
...
SharedModule
],
...
})
export class AppModule { }
in recipes.module import the SharedModule
remove references to CommonModule as it is exported by the shared module
...
import { SharedModule } from '../shared/shared.module';
@NgModule({
declarations: [
...
],
imports: [
ReactiveFormsModule,
RecipesRoutingModule,
SharedModule
],
})
export class RecipesModule { }
Top
Index
loading components via selectors vs routing
for selector have to declare it in the module where it is to be used
can import and export type from different module
Top
Index
understanding lazy loading
lazy loading - feature modules can be loaded as needed
add new component using cli
ng g c home --spec false
in AppRoutingModule change the empty path to the HomeComponent
add a recipe path as shown below
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
import { HomeComponent } from './home/home.component';
const appRoutes: Routes = [
{ path: '', component: HomeComponent },
// loadChildren: < path to feature model >#< class name >
{ path: 'recipe', loadChildren: './recipes/recipes.module#RecipesModule' },
{ path: 'shopping-list', component: ShoppingListComponent },
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
recipe module is now lazily loaded
Top
Index
protecting lazy loading routes with canLoad
route protection on lazily loaded routes can be done using canActivate
better to check that BEFORE loading the code. use the canLoad guard to the route
which points to the lazily loaded module
{ path: 'recipes', loadChildren: './recipes/recipes.module#RecipesModule', canLoad: [AuthGuard] }
AuthGuard needs to implement the CanLoad interface
import { ActivatedRouteSnapshot, CanActivate, CanLoad, Route, RouterStateSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AuthGuard implements CanActivate, CanLoad {
constructor(private authService: AuthService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.authService.isAuthenticated();
}
canLoad(route: Route): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.isAuthenticated();
}
}
add the canLoad property to the JSON object in the app-routing module
...
import { AuthGuard} from './auth/auth-guard.service';
const appRoutes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'recipe', loadChildren: './recipes/recipes.module#RecipesModule', canLoad: [AuthGuard] },
{ path: 'shopping-list', component: ShoppingListComponent },
];
...
export class AppRoutingModule { }
Top
Index
how modules and services work together
consider an app with an eagerly-loaded feature module and a lazily-loaded feature
module
both the app module and the eagerly-loaded feature module have declared a log service
in their providers array
the Root Injector creates one instance of the service at application launch and
both modules share the instance
when the lazily-loaded module is loaded and the log service is injected, the module
will use the same single instance
if the lazily-loaded module has the log service listed in its provider array things
are different
when the module is lazily-loaded Angular will use a Child Injector to create a new
instance of the service
this behavior is only for modules
components use a hierarchital injector
in the first case add a shared module which includes the log service in its providers
array
when the lazily-load module is loaded it gets a different instance of the service
because the child injector is used
don't provide services in shared modules especially if the services are to be used
by lazily-loaded modules
Top
Index
creating a basic core module
core modules only imported by the root module
place for single instance, global services
also be used to export any third party module that is required in the AppModule
Top
Index
using Ahead-of-Time compilation
JIT Compilation
- development
- production
- app downloaded in browser
- Angular parses & compiles templates to JavaScript
Ahead-of-time Compilation
- development
- Angular parses & compiles templates to JavaScript
- production
- app downloaded in browser
advantages of AoT compilation
- faster startup, no compilation in browser
- templates get checked during compilation
- smaller file size, unused features stripped out, compiler isn't shipped
Top
Index
how to use AoT compilation with the CLI
the command
ng build
builds the app for JIT compiling
the command
ng build --prod
tries to optimize and minimize the code
the command
ng build --prod --aot
uses ahead of time compilation
Top
Index
preloading lazy loaded routes
preload lazy loaded modules rather than wait for demand
in app-routing.module add second arg to forRoot method
arg is a JSON object with property called preloadingStrategy
when preloadingStrategy is set to PreloadAllModules lazily loaded modules are loaded
after the app is loaded
...
const appRoutes: Routes = [ ... ];
@NgModule({
imports: [RouterModule.forRoot(appRoutes, { preloadingStrategy: PreloadAllModules })],
exports: [RouterModule]
})
export class AppRoutingModule { }
Top
Index