docs: NgModule guide prose for CLI (partial) (#19776)

Also replaces “Angular Module” with “NgModule” wherever that is clarifying.
Continue using “module” when qualified as in “feature module”, “root module”, “routing module”, etc.

PR Close #19776
This commit is contained in:
Ward Bell
2017-10-17 17:36:22 -07:00
committed by Miško Hevery
parent 69c53c3e03
commit 816d5ba3fd
47 changed files with 1170 additions and 1421 deletions

View File

@ -1,14 +1,19 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
export const routes: Routes = [
import { ContactModule } from './contact/contact.module.3';
const routes: Routes = [
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' },
{ path: 'heroes', loadChildren: 'app/hero/hero.module.3#HeroModule' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
imports: [
ContactModule,
RouterModule.forRoot(routes)
],
exports: [RouterModule]
})
export class AppRoutingModule {}

View File

@ -2,18 +2,29 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
export const routes: Routes = [
import { ContactModule } from './contact/contact.module';
// #docregion routes
const routes: Routes = [
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
// #docregion lazy-routes
// #docregion lazy-routes
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' },
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule' }
// #enddocregion lazy-routes
// #enddocregion lazy-routes
];
// #enddocregion routes
// #docregion forRoot
@NgModule({
imports: [RouterModule.forRoot(routes)],
// #docregion imports
imports: [
ContactModule,
// #docregion forRoot
RouterModule.forRoot(routes),
// #enddocregion forRoot
],
// #enddocregion imports
// #docregion exports
exports: [RouterModule]
// #enddocregion exports
})
export class AppRoutingModule {}
// #enddocregion forRoot

View File

@ -6,5 +6,5 @@ import { Component } from '@angular/core';
template: '<h1>{{title}}</h1>',
})
export class AppComponent {
title = 'Minimal NgModule';
title = 'Angular Modules';
}

View File

@ -11,9 +11,7 @@ import { Component } from '@angular/core';
// #enddocregion template
*/
// #docregion
template: '<app-title [subtitle]="subtitle"></app-title>'
template: '<app-title></app-title>'
})
export class AppComponent {
subtitle = '(v1)';
}
export class AppComponent {}
// #enddocregion

View File

@ -5,11 +5,9 @@ import { Component } from '@angular/core';
selector: 'app-root',
// #docregion template
template: `
<app-title [subtitle]="subtitle"></app-title>
<app-title></app-title>
<app-contact></app-contact>
`
// #enddocregion template
})
export class AppComponent {
subtitle = '(v1)';
}
export class AppComponent {}

View File

@ -3,10 +3,8 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-title [subtitle]="subtitle"></app-title>
<app-title></app-title>
<app-contact></app-contact>
`
})
export class AppComponent {
subtitle = '(v2)';
}
export class AppComponent {}

View File

@ -4,7 +4,7 @@ import { Component } from '@angular/core';
selector: 'app-root',
// #docregion template
template: `
<app-title [subtitle]="subtitle"></app-title>
<app-title></app-title>
<nav>
<a routerLink="contact" routerLinkActive="active">Contact</a>
<a routerLink="crisis" routerLinkActive="active">Crisis Center</a>
@ -14,6 +14,4 @@ import { Component } from '@angular/core';
`
// #enddocregion template
})
export class AppComponent {
subtitle = '(v3)';
}
export class AppComponent {}

View File

@ -5,7 +5,7 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-title [subtitle]="subtitle"></app-title>
<app-title></app-title>
<nav>
<a routerLink="contact" routerLinkActive="active">Contact</a>
<a routerLink="crisis" routerLinkActive="active">Crisis Center</a>
@ -14,6 +14,4 @@ import { Component } from '@angular/core';
<router-outlet></router-outlet>
`
})
export class AppComponent {
subtitle = '(Final)';
}
export class AppComponent {}

View File

@ -1,17 +1,7 @@
// #docplaster
// #docregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import
// #enddocregion
{ AppComponent } from './app.component.0';
/*
// #docregion
{ AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
import { AppComponent } from './app.component.0';
@NgModule({
// #docregion imports

View File

@ -1,14 +1,15 @@
// #docplaster
// #docregion
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import
/* App Imports */
// #enddocregion
{ AppComponent } from './app.component.1';
import { AppComponent } from './app.component.1';
/*
// #docregion
{ AppComponent } from './app.component';
import { AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
@ -21,12 +22,9 @@ import { FormsModule } from '@angular/forms';
import { AwesomePipe } from './contact/awesome.pipe';
import { ContactComponent } from './contact/contact.component.3';
// #docregion import-contact-directive
import {
HighlightDirective as ContactHighlightDirective
} from './contact/highlight.directive';
// #enddocregion import-contact-directive
ContactHighlightDirective as ContactHighlightDirective
} from './contact/contact-highlight.directive';
@NgModule({
// #docregion imports

View File

@ -1,15 +1,16 @@
// #docplaster
// #docregion
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
/* App Root */
import
/* App Imports */
// #enddocregion
{ AppComponent } from './app.component.1b';
import { AppComponent } from './app.component.1b';
/*
// #docregion
{ AppComponent } from './app.component';
import { AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
@ -18,25 +19,17 @@ import { TitleComponent } from './title.component';
import { UserService } from './user.service';
/* Contact Imports */
import
// #enddocregion
{ ContactComponent } from './contact/contact.component.3';
import { ContactComponent } from './contact/contact.component.3';
/*
// #docregion
{ ContactComponent } from './contact/contact.component';
import { ContactComponent } from './contact/contact.component';
// #enddocregion
*/
// #docregion
import { ContactService } from './contact/contact.service';
import { AwesomePipe } from './contact/awesome.pipe';
// #docregion import-alias
import {
HighlightDirective as ContactHighlightDirective
} from './contact/highlight.directive';
// #enddocregion import-alias
import { FormsModule } from '@angular/forms';
import { AwesomePipe } from './contact/awesome.pipe';
import { ContactService } from './contact/contact.service';
import { ContactHighlightDirective } from './contact/contact-highlight.directive';
@NgModule({
imports: [ BrowserModule, FormsModule ],

View File

@ -1,15 +1,15 @@
// #docplaster
// #docregion
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
/* App Root */
import
/* App Imports */
// #enddocregion
{ AppComponent } from './app.component.2';
import { AppComponent } from './app.component.2';
/*
// #docregion
{ AppComponent } from './app.component';
import { AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
@ -18,12 +18,11 @@ import { TitleComponent } from './title.component';
import { UserService } from './user.service';
/* Contact Imports */
import
// #enddocregion
{ ContactModule } from './contact/contact.module.2';
import { ContactModule } from './contact/contact.module.2';
/*
// #docregion
{ ContactModule } from './contact/contact.module';
import { ContactModule } from './contact/contact.module';
// #enddocregion
*/
// #docregion

View File

@ -1,25 +1,36 @@
// #docplaster
// #docregion
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
/* App Root */
/* App Imports */
// #enddocregion
import { AppComponent } from './app.component.3';
/*
// #docregion
import { AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
import { HighlightDirective } from './highlight.directive';
import { TitleComponent } from './title.component';
import { UserService } from './user.service';
/* Feature Modules */
import { ContactModule } from './contact/contact.module.3';
/* Routing Module */
// #enddocregion
import { AppRoutingModule } from './app-routing.module.3';
/*
// #docregion
import { AppRoutingModule } from './app-routing.module';
// #enddocregion
*/
// #docregion
@NgModule({
// #docregion imports
imports: [
BrowserModule,
ContactModule,
AppRoutingModule
],
// #enddocregion imports

View File

@ -1,14 +1,14 @@
// #docplaster
// #docregion
// #docregion v4
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
/* App Root */
/* App Imports */
import { AppComponent } from './app.component';
/* Feature Modules */
import { ContactModule } from './contact/contact.module';
/* Core Modules */
import { CoreModule } from './core/core.module';
/* Routing Module */
@ -18,7 +18,6 @@ import { AppRoutingModule } from './app-routing.module';
// #docregion import-for-root
imports: [
BrowserModule,
ContactModule,
// #enddocregion v4
// #enddocregion import-for-root
/*

View File

@ -1,4 +1,4 @@
/* tslint:disable */
// #docplaster
// Same directive name and selector as
// HighlightDirective in parent AppModule
// It selects for both input boxes and 'highlight' attr
@ -7,12 +7,14 @@
// #docregion
import { Directive, ElementRef } from '@angular/core';
// Highlight the host element or any InputElement in blue
@Directive({ selector: '[highlight], input' })
/** Highlight the attached element or an InputElement in blue */
export class HighlightDirective {
export class ContactHighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'powderblue';
console.log(
`* Contact highlight called for ${el.nativeElement.tagName}`);
// #enddocregion
console.log(`* Contact highlight called for ${el.nativeElement.tagName}`);
// #docregion
}
}
// #enddocregion

View File

@ -3,10 +3,12 @@ import { RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component.3';
const routes = [
{ path: 'contact', component: ContactComponent}
];
@NgModule({
imports: [RouterModule.forChild([
{ path: 'contact', component: ContactComponent}
])],
exports: [RouterModule]
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class ContactRoutingModule {}

View File

@ -4,11 +4,13 @@ import { RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component';
// #docregion routing
const routes = [
{ path: 'contact', component: ContactComponent}
];
@NgModule({
imports: [RouterModule.forChild([
{ path: 'contact', component: ContactComponent }
])],
exports: [RouterModule]
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class ContactRoutingModule {}
// #enddocregion

View File

@ -21,7 +21,7 @@ export class ContactComponent implements OnInit {
}
ngOnInit() {
this.contactService.getContacts().then(contacts => {
this.contactService.getContacts().subscribe(contacts => {
this.msg = '';
this.contacts = contacts;
this.contact = contacts[0];

View File

@ -27,3 +27,6 @@
margin-bottom: 20px;
}
.button-group {
padding-top: 12px;
}

View File

@ -6,18 +6,32 @@
<!-- #docregion awesome -->
<h3 highlight>{{ contact.name | awesome }}</h3>
<!-- #enddocregion awesome -->
<div class="form-group">
<label for="name">Name</label>
<!-- #docregion ngModel -->
<input type="text" class="form-control" required
[(ngModel)]="contact.name"
name="name" #name="ngModel" >
name="name" #name="ngModel" >
<!-- #enddocregion ngModel -->
<div [hidden]="name.valid" class="alert alert-danger">
Name is required
</div>
</div>
<br>
<button type="submit" class="btn btn-default" [disabled]="!contactForm.form.valid">Save</button>
<button type="button" class="btn" (click)="next()" [disabled]="!contactForm.form.valid">Next Contact</button>
<button type="button" class="btn" (click)="newContact()">New Contact</button>
<div class="button-group">
<button type="submit" class="btn btn-default"
[disabled]="!contactForm.form.valid">
Save</button>
<button type="button" class="btn" (click)="next()"
[disabled]="!contactForm.form.valid">
Next Contact</button>
<button type="button" class="btn" (click)="newContact()">
New Contact</button>
</div>
</form>
<!-- #enddocregion -->

View File

@ -22,7 +22,7 @@ export class ContactComponent implements OnInit {
}
ngOnInit() {
this.contactService.getContacts().then(contacts => {
this.contactService.getContacts().subscribe(contacts => {
this.msg = '';
this.contacts = contacts;
this.contact = contacts[0];

View File

@ -0,0 +1,11 @@
// #docregion
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
imports: [
CommonModule
],
declarations: []
})
export class ContactModule { }

View File

@ -5,25 +5,32 @@ import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AwesomePipe } from './awesome.pipe';
import
// #enddocregion
{ ContactComponent } from './contact.component.3';
import { ContactComponent } from './contact.component.3';
/*
// #docregion
{ ContactComponent } from './contact.component';
import { ContactComponent } from './contact.component';
// #enddocregion
*/
// #docregion
import { ContactHighlightDirective } from './contact-highlight.directive';
import { ContactService } from './contact.service';
import { HighlightDirective } from './highlight.directive';
// #docregion class
@NgModule({
imports: [ CommonModule, FormsModule ],
declarations: [ ContactComponent, HighlightDirective, AwesomePipe ],
exports: [ ContactComponent ],
providers: [ ContactService ]
imports: [
CommonModule,
FormsModule
],
declarations: [
AwesomePipe,
ContactComponent,
ContactHighlightDirective
],
// #docregion exports
exports: [ ContactComponent ],
// #enddocregion exports
providers: [ ContactService ]
})
export class ContactModule { }
// #enddocregion class

View File

@ -1,21 +1,43 @@
// #docplaster
// #docregion
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AwesomePipe } from './awesome.pipe';
// #enddocregion
import { ContactComponent } from './contact.component.3';
/*
// #docregion
import { ContactComponent } from './contact.component';
// #enddocregion
*/
// #docregion
import { ContactHighlightDirective } from './contact-highlight.directive';
import { ContactService } from './contact.service';
import { HighlightDirective } from './highlight.directive';
// #enddocregion
import { ContactRoutingModule } from './contact-routing.module.3';
/*
// #docregion
import { ContactRoutingModule } from './contact-routing.module';
// #enddocregion
*/
// #docregion
// #docregion class
@NgModule({
imports: [ CommonModule, FormsModule, ContactRoutingModule ],
declarations: [ ContactComponent, HighlightDirective, AwesomePipe ],
providers: [ ContactService ]
imports: [
CommonModule,
FormsModule,
ContactRoutingModule
],
declarations: [
AwesomePipe,
ContactComponent,
ContactHighlightDirective
],
providers: [ ContactService ]
})
export class ContactModule { }
// #enddocregion class

View File

@ -8,7 +8,10 @@ import { ContactRoutingModule } from './contact-routing.module';
// #docregion class
@NgModule({
imports: [ SharedModule, ContactRoutingModule ],
imports: [
SharedModule,
ContactRoutingModule
],
declarations: [ ContactComponent ],
providers: [ ContactService ]
})

View File

@ -1,5 +1,10 @@
// #docplaster
// #docregion
import { Injectable } from '@angular/core';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { delay } from 'rxjs/operators';
export class Contact {
constructor(public id: number, public name: string) { }
@ -13,17 +18,21 @@ const CONTACTS: Contact[] = [
const FETCH_LATENCY = 500;
/** Simulate a data service that retrieves contacts from a server */
@Injectable()
export class ContactService {
export class ContactService implements OnDestroy {
// #enddocregion
constructor() { console.log('ContactService instance created.'); }
ngOnDestroy() { console.log('ContactService instance destroyed.'); }
getContacts() {
return new Promise<Contact[]>(resolve => {
setTimeout(() => { resolve(CONTACTS); }, FETCH_LATENCY);
});
// #docregion
getContacts(): Observable<Contact[]> {
return of(CONTACTS).pipe(delay(FETCH_LATENCY));
}
getContact(id: number | string) {
return this.getContacts()
.then(heroes => heroes.find(hero => hero.id === +id));
getContact(id: number | string): Observable<Contact> {
return of(CONTACTS.find(contact => contact.id === +id))
.pipe(delay(FETCH_LATENCY));
}
}
// #enddocregion

View File

@ -1,5 +1,5 @@
<!-- Exact copy from earlier app.component.html -->
<h1 highlight>{{title}} {{subtitle}}</h1>
<h1 highlight>{{title}}</h1>
<p *ngIf="user">
<i>Welcome, {{user}}</i>
<p>

View File

@ -7,7 +7,6 @@ import { UserService } from '../core/user.service';
templateUrl: './title.component.html',
})
export class TitleComponent {
@Input() subtitle = '';
title = 'Angular Modules';
user = '';

View File

@ -1,22 +1,21 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Crisis,
CrisisService } from './crisis.service';
CrisisService } from './crisis.service';
@Component({
template: `
<h3 highlight>Crisis List</h3>
<div *ngFor='let crisis of crisises | async'>
<div *ngFor='let crisis of crises | async'>
<a routerLink="{{'../' + crisis.id}}">{{crisis.id}} - {{crisis.name}}</a>
</div>
`
})
export class CrisisListComponent implements OnInit {
crisises: Promise<Crisis[]>;
export class CrisisListComponent {
crises: Observable<Crisis[]>;
constructor(private crisisService: CrisisService) { }
ngOnInit() {
this.crisises = this.crisisService.getCrises();
constructor(private crisisService: CrisisService) {
this.crises = this.crisisService.getCrises();
}
}

View File

@ -1,4 +1,8 @@
import { Injectable } from '@angular/core';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { delay } from 'rxjs/operators';
export class Crisis {
constructor(public id: number, public name: string) { }
@ -13,18 +17,18 @@ const CRISES: Crisis[] = [
const FETCH_LATENCY = 500;
/** Simulate a data service that retrieves crises from a server */
@Injectable()
export class CrisisService {
export class CrisisService implements OnDestroy {
constructor() { console.log('CrisisService instance created.'); }
ngOnDestroy() { console.log('CrisisService instance destroyed.'); }
getCrises() {
return new Promise<Crisis[]>(resolve => {
setTimeout(() => { resolve(CRISES); }, FETCH_LATENCY);
});
getCrises(): Observable<Crisis[]> {
return of(CRISES).pipe(delay(FETCH_LATENCY));
}
getCrisis(id: number | string) {
return this.getCrises()
.then(heroes => heroes.find(hero => hero.id === +id));
getCrisis(id: number | string): Observable<Crisis> {
return of(CRISES.find(crisis => crisis.id === +id))
.pipe(delay(FETCH_LATENCY));
}
}

View File

@ -26,6 +26,6 @@ export class HeroDetailComponent implements OnInit {
ngOnInit() {
let id = parseInt(this.route.snapshot.paramMap.get('id'), 10);
this.heroService.getHero(id).then(hero => this.hero = hero);
this.heroService.getHero(id).subscribe(hero => this.hero = hero);
}
}

View File

@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Hero,
HeroService } from './hero.service';
@ -11,11 +12,9 @@ import { Hero,
</div>
`
})
export class HeroListComponent implements OnInit {
heroes: Promise<Hero[]>;
constructor(private heroService: HeroService) { }
ngOnInit() {
export class HeroListComponent {
heroes: Observable<Hero[]>;
constructor(private heroService: HeroService) {
this.heroes = this.heroService.getHeroes();
}
}

View File

@ -5,9 +5,10 @@ import { FormsModule } from '@angular/forms';
import { HeroComponent } from './hero.component.3';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroListComponent } from './hero-list.component';
import { HighlightDirective } from './highlight.directive';
import { HeroRoutingModule } from './hero-routing.module.3';
import { HighlightDirective } from './highlight.directive';
// #docregion class
@NgModule({
imports: [ CommonModule, FormsModule, HeroRoutingModule ],

View File

@ -1,4 +1,8 @@
import { Injectable } from '@angular/core';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { delay } from 'rxjs/operators';
export class Hero {
constructor(public id: number, public name: string) { }
@ -15,18 +19,19 @@ const HEROES: Hero[] = [
const FETCH_LATENCY = 500;
/** Simulate a data service that retrieves heroes from a server */
@Injectable()
export class HeroService {
export class HeroService implements OnDestroy {
getHeroes() {
return new Promise<Hero[]>(resolve => {
setTimeout(() => { resolve(HEROES); }, FETCH_LATENCY);
});
constructor() { console.log('HeroService instance created.'); }
ngOnDestroy() { console.log('HeroService instance destroyed.'); }
getHeroes(): Observable<Hero[]> {
return of(HEROES).pipe(delay(FETCH_LATENCY));
}
getHero(id: number | string) {
return this.getHeroes()
.then(heroes => heroes.find(hero => hero.id === +id));
getHero(id: number | string): Observable<Hero> {
return of(HEROES.find(hero => hero.id === +id))
.pipe(delay(FETCH_LATENCY));
}
}

View File

@ -1,12 +1,15 @@
// #docplaster
// #docregion
import { Directive, ElementRef } from '@angular/core';
// Highlight the host element in gold
@Directive({ selector: '[highlight]' })
/** Highlight the attached element in gold */
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'gold';
console.log(
`* AppRoot highlight called for ${el.nativeElement.tagName}`);
// #enddocregion
console.log(`* AppRoot highlight called for ${el.nativeElement.tagName}`);
// #docregion
}
}
// #enddocregion

View File

@ -1,9 +1,8 @@
/* tslint:disable */
// Exact copy of contact/highlight.directive except for color and message
import { Directive, ElementRef } from '@angular/core';
@Directive({ selector: '[highlight], input' })
/** Highlight the attached element or an InputElement in gray */
// Highlight the host element or any InputElement in gray
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'lightgray';

View File

@ -1,6 +1,6 @@
<!-- #docregion -->
<!-- #docregion v1 -->
<h1 highlight>{{title}} {{subtitle}}</h1>
<h1 highlight>{{title}}</h1>
<!-- #enddocregion v1 -->
<!-- #docregion ngIf -->
<p *ngIf="user">

View File

@ -1,18 +1,17 @@
// #docplaster
// #docregion
// #docregion v1
import { Component, Input } from '@angular/core';
import { Component } from '@angular/core';
// #enddocregion v1
import { UserService } from './user.service';
// #docregion v1
@Component({
selector: 'app-title',
templateUrl: './title.component.html',
templateUrl: './title.component.html'
})
export class TitleComponent {
@Input() subtitle = '';
title = 'NgModules';
title = 'Angular Modules';
// #enddocregion v1
user = '';