docs: imrpove accessibility of lifecycle hooks example (#41071)

PR Close #41071
This commit is contained in:
Kapunahele Wong 2021-03-03 10:30:47 -05:00 committed by Jessica Janiuk
parent 3ccad85b01
commit 695b72a972
21 changed files with 157 additions and 116 deletions

View File

@ -86,7 +86,7 @@ describe('Lifecycle hooks', () => {
const parentEle = element(by.tagName('after-view-parent'));
const buttonEle = parentEle.element(by.tagName('button')); // Reset
const commentEle = parentEle.element(by.className('comment'));
const logEles = parentEle.all(by.css('h4 ~ div'));
const logEles = parentEle.all(by.css('h3 ~ div'));
const childViewInputEle = parentEle.element(by.css('app-child-view input'));
let logCount: number;
@ -113,7 +113,7 @@ describe('Lifecycle hooks', () => {
const parentEle = element(by.tagName('after-content-parent'));
const buttonEle = parentEle.element(by.tagName('button')); // Reset
const commentEle = parentEle.element(by.className('comment'));
const logEles = parentEle.all(by.css('h4 ~ div'));
const logEles = parentEle.all(by.css('h3 ~ div'));
const childViewInputEle = parentEle.element(by.css('app-child input'));
let logCount = await logEles.count();
@ -136,8 +136,8 @@ describe('Lifecycle hooks', () => {
const inputEle = element(by.css('spy-parent input'));
const addHeroButtonEle = element(by.cssContainingText('spy-parent button', 'Add Hero'));
const resetHeroesButtonEle = element(by.cssContainingText('spy-parent button', 'Reset Heroes'));
const heroEles = element.all(by.css('spy-parent div[appSpy'));
const logEles = element.all(by.css('spy-parent h4 ~ div'));
const heroEles = element.all(by.css('spy-parent div p'));
const logEles = element.all(by.css('spy-parent h3 ~ div'));
expect(await heroEles.count()).toBe(2, 'should have two heroes displayed');
expect(await logEles.count()).toBe(2, 'should have two log entries');
@ -156,18 +156,19 @@ describe('Lifecycle hooks', () => {
it('should support "spy counter"', async () => {
const updateCounterButtonEle = element(by.cssContainingText('counter-parent button', 'Update'));
const resetCounterButtonEle = element(by.cssContainingText('counter-parent button', 'Reset'));
const textEle = element(by.css('counter-parent app-counter > div'));
const logEles = element.all(by.css('counter-parent h4 ~ div'));
const textEle = element(by.css('counter-parent app-counter p'));
const logEles = element.all(by.css('counter-parent .info .log'));
expect(await textEle.getText()).toContain('Counter = 0');
expect(await logEles.count()).toBe(2, 'should start with two log entries');
expect(await logEles.count()).toBe(3, 'should start with one change log and two lifecycle log entries, including reset');
await updateCounterButtonEle.click();
expect(await textEle.getText()).toContain('Counter = 1');
expect(await logEles.count()).toBe(3, 'should now have 3 log entries');
expect(await logEles.count()).toBe(5, 'should now have 2 change log entries and 3 lifecycle log entries, including reset');
await resetCounterButtonEle.click();
expect(await textEle.getText()).toContain('Counter = 0');
expect(await logEles.count()).toBe(7, 'should now have 7 log entries - 3 prev + 1 reset + 2 destroy + 1 init');
expect(await logEles.count()).toBe(8, 'should now have 8 log entries - 1 change log + 2 reset + 2 destroy + 3 init');
});
});

View File

@ -16,12 +16,13 @@ import { LoggerService } from './logger.service';
// #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 class="info">
<h3>AfterContent Logs</h3>
<button (click)="reset()">Reset</button>
<div *ngFor="let msg of logger.logs" class="log">{{msg}}</div>
</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterContentParentComponent {

View File

@ -9,9 +9,9 @@ import { LoggerService } from './logger.service';
selector: 'after-content',
// #docregion template
template: `
<div>-- projected content begins --</div>
<div>projected content begins</div>
<ng-content></ng-content>
<div>-- projected content ends --</div>`
<div>projected content ends</div>`
// #enddocregion template
+ `
<p *ngIf="comment" class="comment">

View File

@ -5,17 +5,16 @@ import { LoggerService } from './logger.service';
@Component({
selector: 'after-view-parent',
template: `
<div class="parent">
<h2>AfterView</h2>
<h2>AfterView</h2>
<after-view *ngIf="show"></after-view>
<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 class="info">
<h3>AfterView Logs</h3>
<button (click)="reset()">Reset</button>
<div *ngFor="let msg of logger.logs" class="log">{{msg}}</div>
</div>
`,
styles: ['.parent {background: burlywood}'],
providers: [LoggerService]
})
export class AfterViewParentComponent {

View File

@ -9,9 +9,9 @@ import { LoggerService } from './logger.service';
selector: 'after-view',
// #docregion template
template: `
<div>-- child view begins --</div>
<div>child view begins</div>
<app-child-view></app-child-view>
<div>-- child view ends --</div>`
<div>child view ends</div>`
// #enddocregion template
+ `
<p *ngIf="comment" class="comment">

View File

@ -1,36 +1,42 @@
<a id="top"></a>
<h1>Component Lifecycle Hooks</h1>
<a href="#hooks">Peek-a-boo: (most) lifecycle hooks</a><br>
<a href="#spy">Spy: directive with OnInit & OnDestroy</a><br>
<a href="#onchanges">OnChanges</a><br>
<a href="#docheck">DoCheck</a><br>
<a href="#after-view">AfterViewInit & AfterViewChecked</a><br>
<a href="#after-content">AfterContentInit & AfterContentChecked</a><br>
<a href="#counter">Counter: OnChanges + Spy directive</a><br>
<h1>Lifecycle Hooks</h1>
<a href="#hooks">Peek-a-boo: (most) lifecycle hooks</a>
<a href="#spy">Spy: directive with OnInit & OnDestroy</a>
<a href="#onchanges">OnChanges</a>
<a href="#docheck">DoCheck</a>
<a href="#after-view">AfterViewInit & AfterViewChecked</a>
<a href="#after-content">AfterContentInit & AfterContentChecked</a>
<a href="#counter">Counter: OnChanges + Spy directive</a>
<a id="hooks"></a>
<peek-a-boo-parent></peek-a-boo-parent>
<a href="#top">back to top</a>
<hr />
<a id="spy"></a>
<spy-parent></spy-parent>
<a href="#top">back to top</a>
<hr />
<a id="onchanges"></a>
<on-changes-parent></on-changes-parent>
<a href="#top">back to top</a>
<hr />
<a id="docheck"></a>
<do-check-parent></do-check-parent>
<a href="#top">back to top</a>
<hr />
<a id="after-view"></a>
<after-view-parent></after-view-parent>
<a href="#top">back to top</a>
<hr />
<a id="after-content"></a>
<after-content-parent></after-content-parent>
<a href="#top">back to top</a>
<hr />
<a id="counter"></a>
<counter-parent></counter-parent>

View File

@ -3,7 +3,8 @@ import { Component } from '@angular/core';
// #docregion child-view
@Component({
selector: 'app-child-view',
template: '<input [(ngModel)]="hero">'
template: `<label for="hero-name">Hero name: </label>
<input type="text" id="hero-name" [(ngModel)]="hero">`
})
export class ChildViewComponent {
hero = 'Magneta';

View File

@ -2,7 +2,8 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-child',
template: '<input [(ngModel)]="hero">'
template: `<label for="hero-name">Hero name: </label>
<input type="text" id="hero-name" [(ngModel)]="hero">`
})
export class ChildComponent {
hero = 'Magneta';

View File

@ -5,19 +5,18 @@ import { LoggerService } from './logger.service';
@Component({
selector: 'counter-parent',
template: `
<div class="parent">
<h2>Counter Spy</h2>
<h2>Counter Spy</h2>
<button (click)="updateCounter()">Update counter</button>
<button (click)="reset()">Reset Counter</button>
<button (click)="updateCounter()">Update counter</button>
<button (click)="reset()">Reset Counter</button>
<app-counter [counter]="value"></app-counter>
<app-counter [counter]="value"></app-counter>
<h4>-- Spy Lifecycle Hook Log --</h4>
<div *ngFor="let msg of spyLog">{{msg}}</div>
<div class="info">
<h3>Spy Lifecycle Hook Log</h3>
<div *ngFor="let msg of spyLog" class="log">{{msg}}</div>
</div>
`,
styles: ['.parent {background: gold;}'],
providers: [LoggerService]
})
export class CounterParentComponent {
@ -38,7 +37,7 @@ export class CounterParentComponent {
}
reset() {
this.logger.log('-- reset --');
this.logger.log('reset');
this.value = 0;
this.logger.tick();
}

View File

@ -7,14 +7,13 @@ import {
@Component({
selector: 'app-counter',
template: `
<div class="counter">
Counter = {{counter}}
<p>Counter = {{counter}}</p>
<h5>-- Counter Change Log --</h5>
<div *ngFor="let chg of changeLog" appSpy>{{chg}}</div>
</div>
`,
styles: ['.counter {background: LightYellow; padding: 8px; margin-top: 8px}']
<div class="info">
<h3>Counter Change Log</h3>
<div *ngFor="let chg of changeLog" appSpy class="log">{{chg}}</div>
</div>
`
})
export class MyCounterComponent implements OnChanges {
@Input() counter: number;

View File

@ -1,11 +1,9 @@
<div class="parent">
<h2>{{title}}</h2>
<h2>{{title}}</h2>
<label for="power-input"><label>Power: </label>
<input type="text" id="power-input" [(ngModel)]="power">
<label for="hero-name">Hero.name: </label>
<input type="text" id="hero-name" [(ngModel)]="hero.name">
<button (click)="reset()">Reset Log</button>
<table>
<tr><td>Power: </td><td><input [(ngModel)]="power"></td></tr>
<tr><td>Hero.name: </td><td><input [(ngModel)]="hero.name"></td></tr>
</table>
<p><button (click)="reset()">Reset Log</button></p>
<do-check [hero]="hero" [power]="power"></do-check>
<do-check [hero]="hero" [power]="power"></do-check>
</div>

View File

@ -5,8 +5,7 @@ import { Hero } from './hero';
@Component({
selector: 'do-check-parent',
templateUrl: './do-check-parent.component.html',
styles: ['.parent {background: Lavender}']
templateUrl: './do-check-parent.component.html'
})
export class DoCheckParentComponent {
hero: Hero;

View File

@ -7,17 +7,13 @@ import { Hero } from './hero';
@Component({
selector: 'do-check',
template: `
<div class="hero">
<div class="info">
<p>{{hero.name}} can {{power}}</p>
<h4>-- Change Log --</h4>
<div *ngFor="let chg of changeLog">{{chg}}</div>
<h3>Change Log</h3>
<div *ngFor="let chg of changeLog" class="log">{{chg}}</div>
</div>
`,
styles: [
'.hero {background: LightYellow; padding: 8px; margin-top: 8px}',
'p {background: Yellow; padding: 8px; margin-top: 8px}'
]
`
})
export class DoCheckComponent implements DoCheck {
@Input() hero: Hero;

View File

@ -1,13 +1,11 @@
<div class="parent">
<h2>{{title}}</h2>
<h2>{{title}}</h2>
<label for="power-input">Power: </label>
<input type="text" id="power-input" [(ngModel)]="power">
<label for="hero-name"> Hero.name: </label>
<input type="text" id="hero-name" [(ngModel)]="hero.name">
<table>
<tr><td>Power: </td><td><input [(ngModel)]="power"></td></tr>
<tr><td>Hero.name: </td><td><input [(ngModel)]="hero.name"></td></tr>
</table>
<p><button (click)="reset()">Reset Log</button></p>
<button (click)="reset()">Reset Log</button>
<!-- #docregion on-changes -->
<on-changes [hero]="hero" [power]="power"></on-changes>
<!-- #enddocregion on-changes -->
</div>
<!-- #docregion on-changes -->
<on-changes [hero]="hero" [power]="power"></on-changes>
<!-- #enddocregion on-changes -->

View File

@ -6,7 +6,7 @@ import { OnChangesComponent } from './on-changes.component';
@Component({
selector: 'on-changes-parent',
templateUrl: './on-changes-parent.component.html',
styles: ['.parent {background: Lavender;}']
styles: ['']
})
export class OnChangesParentComponent {
hero: Hero;

View File

@ -7,17 +7,13 @@ import { Hero } from './hero';
@Component({
selector: 'on-changes',
template: `
<div class="hero">
<div class="info">
<p>{{hero.name}} can {{power}}</p>
<h4>-- Change Log --</h4>
<div *ngFor="let chg of changeLog">{{chg}}</div>
<h3>Change Log</h3>
<div *ngFor="let chg of changeLog" class="log">{{chg}}</div>
</div>
`,
styles: [
'.hero {background: LightYellow; padding: 8px; margin-top: 8px}',
'p {background: Yellow; padding: 8px; margin-top: 8px}'
]
`
})
export class OnChangesComponent implements OnChanges {
// #docregion inputs

View File

@ -6,6 +6,7 @@ import { LoggerService } from './logger.service';
@Component({
selector: 'peek-a-boo-parent',
template: `
<hr />
<div class="parent">
<h2>Peek-A-Boo</h2>
@ -14,14 +15,14 @@ import { LoggerService } from './logger.service';
</button>
<button (click)="updateHero()" [hidden]="!hasChild">Update Hero</button>
<peek-a-boo *ngIf="hasChild" [name]="heroName">
</peek-a-boo>
<div class="info">
<peek-a-boo *ngIf="hasChild" [name]="heroName"></peek-a-boo>
<h4>-- Lifecycle Hook Log --</h4>
<div *ngFor="let msg of hookLog">{{msg}}</div>
<h3>Lifecycle Hook Log</h3>
<div *ngFor="let msg of hookLog" class="log">{{msg}}</div>
</div>
</div>
`,
styles: ['.parent {background: moccasin}'],
providers: [ LoggerService ]
})
export class PeekABooParentComponent {

View File

@ -19,8 +19,7 @@ import { PeekABooDirective } from './peek-a-boo.directive';
@Component({
selector: 'peek-a-boo',
template: '<p>Now you see my hero, {{name}}</p>',
styles: ['p {background: LightYellow; padding: 8px}']
template: '<p>Now you see my hero, {{name}}</p>'
})
// Don't HAVE to mention the Lifecycle Hook interfaces
// unless we want typing and tool support.

View File

@ -1,16 +1,19 @@
<div class="parent">
<h2>Spy Directive</h2>
<input [(ngModel)]="newName" (keyup.enter)="addHero()">
<label for="hero-name">Hero name: </label>
<input type="text" id="hero-name" [(ngModel)]="newName" (keyup.enter)="addHero()">
<button (click)="addHero()">Add Hero</button>
<button (click)="reset()">Reset Heroes</button>
<p></p>
<!-- #docregion template -->
<div *ngFor="let hero of heroes" appSpy class="heroes">
{{hero}}
<div class="info">
<!-- #docregion template -->
<p *ngFor="let hero of heroes" appSpy>
{{hero}}
</p>
<!-- #enddocregion template -->
<h3>Spy Lifecycle Hook Log</h3>
<div *ngFor="let msg of logger.logs" class="log">{{msg}}</div>
</div>
<!-- #enddocregion template -->
<h4>-- Spy Lifecycle Hook Log --</h4>
<div *ngFor="let msg of logger.logs">{{msg}}</div>
</div>

View File

@ -6,10 +6,6 @@ import { LoggerService } from './logger.service';
@Component({
selector: 'spy-parent',
templateUrl: './spy.component.html',
styles: [
'.parent {background: khaki;}',
'.heroes {background: LightYellow; padding: 0 8px}'
],
providers: [LoggerService]
})
export class SpyParentComponent {
@ -31,7 +27,7 @@ export class SpyParentComponent {
this.logger.tick();
}
reset() {
this.logger.log('-- reset --');
this.logger.log('reset');
this.heroes = [];
this.logger.tick();
}

View File

@ -1,13 +1,61 @@
.parent {
color: #666;
margin: 14px 0;
padding: 8px;
padding: 2rem 0;
}
input {
margin: 4px;
padding: 4px;
h2 {
text-align: center;
}
.comment {
color: red;
color: #890000;
font-style: italic;
}
.log {
background-color: #e4e4e4;
padding: .25rem;
}
.info {
background: #fff4f4;
padding: .75rem;
margin-top: 1rem;
}
p {
padding: .25rem;
}
a {
display: block;
padding-bottom: .5rem;
font-size: 1.1rem;
color: #264d73
}
a:hover {
text-decoration: none;
}
a[href="#top"] {
margin: 1rem 0;
padding: .5rem;
background-color: #264d73;
color: #fff;
}
a[href="#top"]:hover {
background-color:#eaeaea;
color: black;
}
a[href="#top"]:active {
background-color: black;
color: #eaeaea;
}
input {
margin-bottom: 1rem;
margin-top: .5rem;
font-size: 1rem;
}