docs: lifecycle-hooks example - extract things (components, directives) into their own files (#40212)

This change is in line with Angular Style Guide rule 01-01
https://angular.io/guide/styleguide#style-01-01.

PR Close #40212
This commit is contained in:
Alexey Elin 2020-12-20 00:23:14 +03:00 committed by atscott
parent 9be9e466b1
commit aea265bfc5
17 changed files with 242 additions and 233 deletions

View File

@ -0,0 +1,38 @@
import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'after-content-parent',
template: `
<div class="parent">
<h2>AfterContent</h2>
<div *ngIf="show">` +
// #docregion parent-template
`<after-content>
<app-child></app-child>
</after-content>`
// #enddocregion parent-template
+ `</div>
<h4>-- AfterContent Logs --</h4>
<p><button (click)="reset()">Reset</button></p>
<div *ngFor="let msg of logger.logs">{{msg}}</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterContentParentComponent {
show = true;
constructor(public logger: LoggerService) { }
reset() {
this.logger.clear();
// quickly remove and reload AfterContentComponent which recreates it
this.show = false;
this.logger.tick_then(() => this.show = true);
}
}

View File

@ -2,18 +2,9 @@
// #docregion // #docregion
import { AfterContentChecked, AfterContentInit, Component, ContentChild } from '@angular/core'; import { AfterContentChecked, AfterContentInit, Component, ContentChild } from '@angular/core';
import { ChildComponent } from './child.component';
import { LoggerService } from './logger.service'; import { LoggerService } from './logger.service';
//////////////////
@Component({
selector: 'app-child',
template: '<input [(ngModel)]="hero">'
})
export class ChildComponent {
hero = 'Magneta';
}
//////////////////////
@Component({ @Component({
selector: 'after-content', selector: 'after-content',
// #docregion template // #docregion template
@ -75,40 +66,3 @@ export class AfterContentComponent implements AfterContentChecked, AfterContentI
// ... // ...
} }
// #enddocregion hooks // #enddocregion hooks
//////////////
@Component({
selector: 'after-content-parent',
template: `
<div class="parent">
<h2>AfterContent</h2>
<div *ngIf="show">` +
// #docregion parent-template
`<after-content>
<app-child></app-child>
</after-content>`
// #enddocregion parent-template
+ `</div>
<h4>-- AfterContent Logs --</h4>
<p><button (click)="reset()">Reset</button></p>
<div *ngFor="let msg of logger.logs">{{msg}}</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterContentParentComponent {
show = true;
constructor(public logger: LoggerService) {
}
reset() {
this.logger.clear();
// quickly remove and reload AfterContentComponent which recreates it
this.show = false;
this.logger.tick_then(() => this.show = true);
}
}

View File

@ -0,0 +1,32 @@
import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'after-view-parent',
template: `
<div class="parent">
<h2>AfterView</h2>
<after-view *ngIf="show"></after-view>
<h4>-- AfterView Logs --</h4>
<p><button (click)="reset()">Reset</button></p>
<div *ngFor="let msg of logger.logs">{{msg}}</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterViewParentComponent {
show = true;
constructor(public logger: LoggerService) { }
reset() {
this.logger.clear();
// quickly remove and reload AfterViewComponent which recreates it
this.show = false;
this.logger.tick_then(() => this.show = true);
}
}

View File

@ -2,20 +2,9 @@
// #docregion // #docregion
import { AfterViewChecked, AfterViewInit, Component, ViewChild } from '@angular/core'; import { AfterViewChecked, AfterViewInit, Component, ViewChild } from '@angular/core';
import { ChildViewComponent } from './child-view.component';
import { LoggerService } from './logger.service'; import { LoggerService } from './logger.service';
//////////////////
// #docregion child-view
@Component({
selector: 'app-child-view',
template: '<input [(ngModel)]="hero">'
})
export class ChildViewComponent {
hero = 'Magneta';
}
// #enddocregion child-view
//////////////////////
@Component({ @Component({
selector: 'after-view', selector: 'after-view',
// #docregion template // #docregion template
@ -84,34 +73,3 @@ export class AfterViewComponent implements AfterViewChecked, AfterViewInit {
// ... // ...
} }
// #enddocregion hooks // #enddocregion hooks
//////////////
@Component({
selector: 'after-view-parent',
template: `
<div class="parent">
<h2>AfterView</h2>
<after-view *ngIf="show"></after-view>
<h4>-- AfterView Logs --</h4>
<p><button (click)="reset()">Reset</button></p>
<div *ngFor="let msg of logger.logs">{{msg}}</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterViewParentComponent {
show = true;
constructor(public logger: LoggerService) {
}
reset() {
this.logger.clear();
// quickly remove and reload AfterViewComponent which recreates it
this.show = false;
this.logger.tick_then(() => this.show = true);
}
}

View File

@ -5,32 +5,22 @@ import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { import { AfterContentParentComponent } from './after-content-parent.component';
AfterContentParentComponent, import { AfterContentComponent } from './after-content.component';
AfterContentComponent, import { ChildComponent } from './child.component';
ChildComponent
} from './after-content.component';
import { import { AfterViewParentComponent } from './after-view-parent.component';
AfterViewParentComponent, import { AfterViewComponent } from './after-view.component';
AfterViewComponent, import { ChildViewComponent } from './child-view.component';
ChildViewComponent
} from './after-view.component';
import { import { CounterParentComponent } from './counter-parent.component';
CounterParentComponent, import { MyCounterComponent } from './counter.component';
MyCounterComponent
} from './counter.component';
import { import { DoCheckParentComponent } from './do-check-parent.component';
DoCheckParentComponent, import { DoCheckComponent } from './do-check.component';
DoCheckComponent
} from './do-check.component';
import { import { OnChangesParentComponent } from './on-changes-parent.component';
OnChangesParentComponent, import { OnChangesComponent } from './on-changes.component';
OnChangesComponent
} from './on-changes.component';
import { PeekABooParentComponent } from './peek-a-boo-parent.component'; import { PeekABooParentComponent } from './peek-a-boo-parent.component';
import { PeekABooComponent } from './peek-a-boo.component'; import { PeekABooComponent } from './peek-a-boo.component';

View File

@ -0,0 +1,11 @@
import { Component } from '@angular/core';
// #docregion child-view
@Component({
selector: 'app-child-view',
template: '<input [(ngModel)]="hero">'
})
export class ChildViewComponent {
hero = 'Magneta';
}
// #enddocregion child-view

View File

@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-child',
template: '<input [(ngModel)]="hero">'
})
export class ChildComponent {
hero = 'Magneta';
}

View File

@ -0,0 +1,45 @@
import { Component } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({
selector: 'counter-parent',
template: `
<div class="parent">
<h2>Counter Spy</h2>
<button (click)="updateCounter()">Update counter</button>
<button (click)="reset()">Reset Counter</button>
<app-counter [counter]="value"></app-counter>
<h4>-- Spy Lifecycle Hook Log --</h4>
<div *ngFor="let msg of spyLog">{{msg}}</div>
</div>
`,
styles: ['.parent {background: gold;}'],
providers: [LoggerService]
})
export class CounterParentComponent {
value: number;
spyLog: string[] = [];
private logger: LoggerService;
constructor(logger: LoggerService) {
this.logger = logger;
this.spyLog = logger.logs;
this.reset();
}
updateCounter() {
this.value += 1;
this.logger.tick();
}
reset() {
this.logger.log('-- reset --');
this.value = 0;
this.logger.tick();
}
}

View File

@ -4,8 +4,6 @@ import {
OnChanges, SimpleChanges, OnChanges, SimpleChanges,
} from '@angular/core'; } from '@angular/core';
import { LoggerService } from './logger.service';
@Component({ @Component({
selector: 'app-counter', selector: 'app-counter',
template: ` template: `
@ -37,46 +35,3 @@ export class MyCounterComponent implements OnChanges {
this.changeLog.push(`counter: currentValue = ${cur}, previousValue = ${prev}`); this.changeLog.push(`counter: currentValue = ${cur}, previousValue = ${prev}`);
} }
} }
@Component({
selector: 'counter-parent',
template: `
<div class="parent">
<h2>Counter Spy</h2>
<button (click)="updateCounter()">Update counter</button>
<button (click)="reset()">Reset Counter</button>
<app-counter [counter]="value"></app-counter>
<h4>-- Spy Lifecycle Hook Log --</h4>
<div *ngFor="let msg of spyLog">{{msg}}</div>
</div>
`,
styles: ['.parent {background: gold;}'],
providers: [LoggerService]
})
export class CounterParentComponent {
value: number;
spyLog: string[] = [];
private logger: LoggerService;
constructor(logger: LoggerService) {
this.logger = logger;
this.spyLog = logger.logs;
this.reset();
}
updateCounter() {
this.value += 1;
this.logger.tick();
}
reset() {
this.logger.log('-- reset --');
this.value = 0;
this.logger.tick();
}
}

View File

@ -0,0 +1,28 @@
import { Component, ViewChild } from '@angular/core';
import { DoCheckComponent } from './do-check.component';
import { Hero } from './hero';
@Component({
selector: 'do-check-parent',
templateUrl: './do-check-parent.component.html',
styles: ['.parent {background: Lavender}']
})
export class DoCheckParentComponent {
hero: Hero;
power: string;
title = 'DoCheck';
@ViewChild(DoCheckComponent) childView: DoCheckComponent;
constructor() {
this.reset();
}
reset() {
this.hero = new Hero('Windstorm');
this.power = 'sing';
if (this.childView) {
this.childView.reset();
}
}
}

View File

@ -1,10 +1,8 @@
/* tslint:disable:forin */ /* tslint:disable:forin */
// #docregion // #docregion
import { Component, DoCheck, Input, ViewChild } from '@angular/core'; import { Component, DoCheck, Input } from '@angular/core';
class Hero { import { Hero } from './hero';
constructor(public name: string) {}
}
@Component({ @Component({
selector: 'do-check', selector: 'do-check',
@ -71,23 +69,3 @@ export class DoCheckComponent implements DoCheck {
this.changeLog = []; this.changeLog = [];
} }
} }
@Component({
selector: 'do-check-parent',
templateUrl: './do-check-parent.component.html',
styles: ['.parent {background: Lavender}']
})
export class DoCheckParentComponent {
hero: Hero;
power: string;
title = 'DoCheck';
@ViewChild(DoCheckComponent) childView: DoCheckComponent;
constructor() { this.reset(); }
reset() {
this.hero = new Hero('Windstorm');
this.power = 'sing';
if (this.childView) { this.childView.reset(); }
}
}

View File

@ -0,0 +1,3 @@
export class Hero {
constructor(public name: string) { }
}

View File

@ -0,0 +1,30 @@
import { Component, ViewChild } from '@angular/core';
import { Hero } from './hero';
import { OnChangesComponent } from './on-changes.component';
@Component({
selector: 'on-changes-parent',
templateUrl: './on-changes-parent.component.html',
styles: ['.parent {background: Lavender;}']
})
export class OnChangesParentComponent {
hero: Hero;
power: string;
title = 'OnChanges';
@ViewChild(OnChangesComponent) childView: OnChangesComponent;
constructor() {
this.reset();
}
reset() {
// new Hero object every time; triggers onChanges
this.hero = new Hero('Windstorm');
// setting power only triggers onChanges if this value is different
this.power = 'sing';
if (this.childView) {
this.childView.reset();
}
}
}

View File

@ -1,13 +1,8 @@
/* tslint:disable:forin */ /* tslint:disable:forin */
// #docregion // #docregion
import { import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
Component, Input, OnChanges,
SimpleChanges, ViewChild
} from '@angular/core';
class Hero { import { Hero } from './hero';
constructor(public name: string) {}
}
@Component({ @Component({
selector: 'on-changes', selector: 'on-changes',
@ -45,27 +40,3 @@ export class OnChangesComponent implements OnChanges {
reset() { this.changeLog = []; } reset() { this.changeLog = []; }
} }
@Component({
selector: 'on-changes-parent',
templateUrl: './on-changes-parent.component.html',
styles: ['.parent {background: Lavender;}']
})
export class OnChangesParentComponent {
hero: Hero;
power: string;
title = 'OnChanges';
@ViewChild(OnChangesComponent) childView: OnChangesComponent;
constructor() {
this.reset();
}
reset() {
// new Hero object every time; triggers onChanges
this.hero = new Hero('Windstorm');
// setting power only triggers onChanges if this value is different
this.power = 'sing';
if (this.childView) { this.childView.reset(); }
}
}

View File

@ -5,31 +5,17 @@ import {
AfterContentInit, AfterContentInit,
AfterViewChecked, AfterViewChecked,
AfterViewInit, AfterViewInit,
Directive, Component,
DoCheck, DoCheck,
Input,
OnChanges, OnChanges,
OnDestroy, OnDestroy,
OnInit, OnInit,
SimpleChanges SimpleChanges
} from '@angular/core'; } from '@angular/core';
import { Component, Input } from '@angular/core';
import { LoggerService } from './logger.service'; import { LoggerService } from './logger.service';
import { PeekABooDirective } from './peek-a-boo.directive';
let nextId = 1;
// #docregion ngOnInit
@Directive()
export class PeekABooDirective implements OnInit {
constructor(private logger: LoggerService) { }
// implement OnInit's `ngOnInit` method
ngOnInit() { this.logIt(`OnInit`); }
logIt(msg: string) {
this.logger.log(`#${nextId++} ${msg}`);
}
}
// #enddocregion ngOnInit
@Component({ @Component({
selector: 'peek-a-boo', selector: 'peek-a-boo',

View File

@ -0,0 +1,21 @@
import { Directive, OnInit } from '@angular/core';
import { LoggerService } from './logger.service';
let nextId = 1;
// #docregion ngOnInit
@Directive()
export class PeekABooDirective implements OnInit {
constructor(private logger: LoggerService) { }
// implement OnInit's `ngOnInit` method
ngOnInit() {
this.logIt(`OnInit`);
}
logIt(msg: string) {
this.logger.log(`#${nextId++} ${msg}`);
}
}
// #enddocregion ngOnInit

View File

@ -24,7 +24,7 @@ The hooks give you the opportunity to act on a component or directive instance a
Each interface defines the prototype for a single hook method, whose name is the interface name prefixed with `ng`. Each interface defines the prototype for a single hook method, whose name is the interface name prefixed with `ng`.
For example, the `OnInit` interface has a hook method named `ngOnInit()`. If you implement this method in your component or directive class, Angular calls it shortly after checking the input properties for that component or directive for the first time. For example, the `OnInit` interface has a hook method named `ngOnInit()`. If you implement this method in your component or directive class, Angular calls it shortly after checking the input properties for that component or directive for the first time.
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" header="peek-a-boo.component.ts (excerpt)"></code-example> <code-example path="lifecycle-hooks/src/app/peek-a-boo.directive.ts" region="ngOnInit" header="peek-a-boo.directive.ts (excerpt)"></code-example>
You don't have to implement all (or any) of the lifecycle hooks, just the ones you need. You don't have to implement all (or any) of the lifecycle hooks, just the ones you need.
@ -464,7 +464,7 @@ The *AfterView* sample explores the `AfterViewInit()` and `AfterViewChecked()` h
Here's a child view that displays a hero's name in an `<input>`: Here's a child view that displays a hero's name in an `<input>`:
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" header="ChildComponent"></code-example> <code-example path="lifecycle-hooks/src/app/child-view.component.ts" region="child-view" header="ChildViewComponent"></code-example>
The `AfterViewComponent` displays this child view *within its template*: The `AfterViewComponent` displays this child view *within its template*:
@ -528,7 +528,7 @@ This time, instead of including the child view within the template, it imports t
the `AfterContentComponent`'s parent. the `AfterContentComponent`'s parent.
The following is the parent's template. The following is the parent's template.
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" header="AfterContentParentComponent (template excerpt)"></code-example> <code-example path="lifecycle-hooks/src/app/after-content-parent.component.ts" region="parent-template" header="AfterContentParentComponent (template excerpt)"></code-example>
Notice that the `<app-child>` tag is tucked between the `<after-content>` tags. Notice that the `<app-child>` tag is tucked between the `<after-content>` tags.
Never put content between a component's element tags *unless you intend to project that content Never put content between a component's element tags *unless you intend to project that content