Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit b5ea1d8

Browse files
filipesilvawardbell
authored andcommitted
docs(lifecycle-hooks): add hook sections, revise sample, add DoCheck & tests
1 parent 2929255 commit b5ea1d8

28 files changed

+1086
-384
lines changed

public/docs/_examples/lifecycle-hooks/e2e-spec.js

Lines changed: 77 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe('Lifecycle hooks', function () {
88
expect(element.all(by.css('h2')).get(0).getText()).toEqual('Peek-A-Boo');
99
});
1010

11-
it('should be able to drive peek-a-boo button', function () {
11+
it('should support peek-a-boo', function () {
1212
var pabComp = element(by.css('peek-a-boo-parent peek-a-boo'));
1313
expect(pabComp.isPresent()).toBe(false, "should not be able to find the 'peek-a-boo' component");
1414
var pabButton = element.all(by.css('peek-a-boo-parent button')).get(0);
@@ -29,80 +29,118 @@ describe('Lifecycle hooks', function () {
2929
});
3030
});
3131

32-
it('should be able to trigger onChanges', function () {
33-
var onChangesViewEle = element.all(by.css('on-changes-parent my-hero div')).get(0);
32+
it('should support OnChanges hook', function () {
33+
var onChangesViewEle = element.all(by.css('on-changes div')).get(0);
3434
var inputEles = element.all(by.css('on-changes-parent input'));
35-
var heroNameInputEle = inputEles.get(0);
36-
var powerInputEle = inputEles.get(1);
35+
var heroNameInputEle = inputEles.get(1);
36+
var powerInputEle = inputEles.get(0);
3737
var titleEle = onChangesViewEle.element(by.css('p'));
38-
expect(titleEle.getText()).toContain('Windstorm can sing');
3938
var changeLogEles = onChangesViewEle.all(by.css('div'));
40-
expect(changeLogEles.count()).toEqual(3, "should start with 3 messages");
39+
40+
expect(titleEle.getText()).toContain('Windstorm can sing');
41+
expect(changeLogEles.count()).toEqual(2, "should start with 2 messages");
4142
// heroNameInputEle.sendKeys('-foo-').then(function () {
4243
sendKeys(heroNameInputEle, '-foo-').then(function () {
4344
expect(titleEle.getText()).toContain('Windstorm-foo- can sing');
44-
expect(changeLogEles.count()).toEqual(3, "should still have 3 messages");
45+
expect(changeLogEles.count()).toEqual(2, "should still have 2 messages");
4546
// protractor bug with sendKeys means that line below does not work.
4647
// return powerInputEle.sendKeys('-bar-');
4748
return sendKeys(powerInputEle, '-bar-');
4849
}).then(function () {
4950
expect(titleEle.getText()).toContain('Windstorm-foo- can sing-bar-');
50-
// 8 == 3 previously + length of '-bar-'
51-
expect(changeLogEles.count()).toEqual(8, "should have 8 messages now");
51+
// 7 == 2 previously + length of '-bar-'
52+
expect(changeLogEles.count()).toEqual(7, "should have 7 messages now");
5253
});
5354
});
54-
55-
it('should support after-view hooks', function () {
56-
var inputEle = element(by.css('after-view-parent input'));
57-
var buttonEle = element(by.css('after-view-parent button'));
58-
var logEles = element.all(by.css('after-view-parent h4 ~ div'));
59-
var childViewTextEle = element(by.css('after-view-parent my-child .child'));
60-
expect(childViewTextEle.getText()).toContain('Magneta is my hero');
61-
expect(logEles.count()).toBeGreaterThan(2);
55+
56+
it('should support DoCheck hook', function () {
57+
var doCheckViewEle = element.all(by.css('do-check div')).get(0);
58+
var inputEles = element.all(by.css('do-check-parent input'));
59+
var heroNameInputEle = inputEles.get(1);
60+
var powerInputEle = inputEles.get(0);
61+
var titleEle = doCheckViewEle.element(by.css('p'));
62+
var changeLogEles = doCheckViewEle.all(by.css('div'));
63+
var logCount;
64+
65+
expect(titleEle.getText()).toContain('Windstorm can sing');
66+
changeLogEles.count().then(function(count) {
67+
expect(count).toBeGreaterThan(3, "should start with at least 4 messages");
68+
logCount = count;
69+
// heroNameInputEle.sendKeys('-foo-').then(function () {
70+
return sendKeys(heroNameInputEle, '-foo-')
71+
}).then(function () {
72+
expect(titleEle.getText()).toContain('Windstorm-foo- can sing');
73+
return changeLogEles.count()
74+
}).then(function (count) {
75+
expect(count).toEqual(logCount + 10, 'should add 10 more messages')
76+
logCount = count;
77+
// return powerInputEle.sendKeys('-bar-');
78+
return sendKeys(powerInputEle, '-bar-');
79+
}).then(function () {
80+
expect(titleEle.getText()).toContain('Windstorm-foo- can sing-bar-');
81+
// 7 == 2 previously + length of '-bar-'
82+
expect(changeLogEles.count()).toEqual(logCount + 15, 'should add 15 more messages');
83+
});
84+
});
85+
86+
it('should support AfterView hooks', function () {
87+
var parentEle = element(by.tagName('after-view-parent'));
88+
var buttonEle = parentEle.element(by.tagName('button')); // Reset
89+
var commentEle = parentEle.element(by.className('comment'));
90+
var logEles = parentEle.all(by.css('h4 ~ div'));
91+
var childViewInputEle = parentEle.element(by.css('my-child input'));
6292
var logCount;
93+
94+
expect(childViewInputEle.getAttribute('value')).toContain('Magneta');
95+
expect(commentEle.isPresent()).toBe(false, 'comment should not be in DOM');
96+
6397
logEles.count().then(function(count) {
6498
logCount = count;
65-
return sendKeys(inputEle, "-test-");
99+
return sendKeys(childViewInputEle, "-test-");
66100
}).then(function() {
67-
expect(childViewTextEle.getText()).toContain('-test-');
101+
expect(childViewInputEle.getAttribute('value')).toContain('-test-');
102+
expect(commentEle.isPresent()).toBe(true,'should have comment because >10 chars');
103+
expect(commentEle.getText()).toContain('long name');
68104
return logEles.count();
69105
}).then(function(count) {
70-
expect(logCount + 6).toEqual(count, "6 additional log messages should have been added");
106+
expect(logCount + 11).toEqual(count, "11 additional log messages should have been added");
71107
logCount = count;
72108
return buttonEle.click();
73109
}).then(function() {
74-
expect(childViewTextEle.isPresent()).toBe(false,"child view should no longer be part of the DOM");
75-
sendKeys(inputEle, "-foo-");
76-
expect(logEles.count()).toEqual(logCount, "no additional log messages should have been added");
110+
expect(logEles.count()).toBeLessThan(logCount, "log should shrink after reset");
77111
});
78112
});
79113

80-
it('should support after-content hooks', function () {
81-
var inputEle = element(by.css('after-content-parent input'));
82-
var buttonEle = element(by.css('after-content-parent button'));
83-
var logEles = element.all(by.css('after-content-parent h4 ~ div'));
84-
var childViewTextEle = element(by.css('after-content-parent my-child .child'));
85-
expect(childViewTextEle.getText()).toContain('Magneta is my hero');
86-
expect(logEles.count()).toBeGreaterThan(2);
114+
115+
it('should support AfterContent hooks', function () {
116+
var parentEle = element(by.tagName('after-content-parent'));
117+
var buttonEle = parentEle.element(by.tagName('button')); // Reset
118+
var commentEle = parentEle.element(by.className('comment'));
119+
var logEles = parentEle.all(by.css('h4 ~ div'));
120+
var childViewInputEle = parentEle.element(by.css('my-child input'));
87121
var logCount;
122+
123+
expect(childViewInputEle.getAttribute('value')).toContain('Magneta');
124+
expect(commentEle.isPresent()).toBe(false, 'comment should not be in DOM');
125+
88126
logEles.count().then(function(count) {
89127
logCount = count;
90-
return sendKeys(inputEle, "-test-");
128+
return sendKeys(childViewInputEle, "-test-");
91129
}).then(function() {
92-
expect(childViewTextEle.getText()).toContain('-test-');
130+
expect(childViewInputEle.getAttribute('value')).toContain('-test-');
131+
expect(commentEle.isPresent()).toBe(true,'should have comment because >10 chars');
132+
expect(commentEle.getText()).toContain('long name');
93133
return logEles.count();
94134
}).then(function(count) {
95-
expect(logCount + 6).toEqual(count, "6 additional log messages should have been added");
135+
expect(logCount + 11).toEqual(count, "11 additional log messages should have been added");
96136
logCount = count;
97137
return buttonEle.click();
98138
}).then(function() {
99-
expect(childViewTextEle.isPresent()).toBe(false,"child view should no longer be part of the DOM");
100-
sendKeys(inputEle, "-foo-");
101-
expect(logEles.count()).toEqual(logCount, "no additional log messages should have been added");
139+
expect(logEles.count()).toBeLessThan(logCount, "log should shrink after reset");
102140
});
103141
});
104142

105-
it('should support "spy" hooks', function () {
143+
it('should support spy\'s OnInit & OnDestroy hooks', function () {
106144
var inputEle = element(by.css('spy-parent input'));
107145
var addHeroButtonEle = element(by.cssContainingText('spy-parent button','Add Hero'));
108146
var resetHeroesButtonEle = element(by.cssContainingText('spy-parent button','Reset Heroes'));
@@ -123,7 +161,7 @@ describe('Lifecycle hooks', function () {
123161
})
124162
});
125163

126-
it('should support "spy counter" hooks', function () {
164+
it('should support "spy counter"', function () {
127165
var updateCounterButtonEle = element(by.cssContainingText('counter-parent button','Update'));
128166
var resetCounterButtonEle = element(by.cssContainingText('counter-parent button','Reset'));
129167
var textEle = element(by.css('counter-parent my-counter > div'));
Lines changed: 83 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,119 @@
1+
// #docplaster
12
// #docregion
2-
import {
3-
Component, Input, Output,
4-
AfterContentChecked, AfterContentInit, ContentChild,
5-
AfterViewInit, ViewChild
6-
} from 'angular2/core';
3+
import {Component, AfterContentChecked, AfterContentInit, ContentChild} from 'angular2/core';
74

8-
import {ChildComponent} from './child.component';
95
import {LoggerService} from './logger.service';
106

7+
//////////////////
118
@Component({
12-
selector: 'after-content',
13-
template: `
14-
<div class="after-content">
15-
<div>-- child content begins --</div>
16-
17-
<ng-content></ng-content>
18-
19-
<div>-- child content ends --</div>
20-
</div>
21-
`,
22-
styles: ['.after-content {background: LightCyan; padding: 8px;}'],
23-
9+
selector: 'my-child',
10+
template: '<input [(ngModel)]="hero">'
2411
})
25-
export class AfterContentComponent
26-
implements AfterContentChecked, AfterContentInit, AfterViewInit {
27-
28-
private _logger:LoggerService;
12+
export class ChildComponent {
13+
hero = 'Magneta';
14+
}
2915

30-
constructor(logger:LoggerService){
31-
this._logger = logger;
32-
logger.log('AfterContent ctor: ' + this._getMessage());
33-
}
16+
//////////////////////
17+
@Component({
18+
selector: 'after-content',
19+
// #docregion template
20+
template:`
21+
<div>-- projected content begins --</div>
22+
<ng-content></ng-content>
23+
<div>-- projected content ends --</div>`
24+
// #enddocregion template
25+
+ `
26+
<p *ngIf="comment" class="comment">
27+
{{comment}}
28+
</p>
29+
`
30+
})
31+
// #docregion hooks
32+
export class AfterContentComponent implements AfterContentChecked, AfterContentInit {
33+
private _prevHero = '';
3434

3535
// Query for a CONTENT child of type `ChildComponent`
3636
@ContentChild(ChildComponent) contentChild: ChildComponent;
3737

38-
// Query for a VIEW child of type`ChildComponent`
39-
// No such VIEW child exists!
40-
// This component holds content but no view of that type.
41-
@ViewChild(ChildComponent) viewChild: ChildComponent;
42-
43-
44-
///// Hooks
45-
ngAfterContentInit() {
46-
// contentChild is set after the content has been initialized
47-
this._logger.log('AfterContentInit: ' + this._getMessage());
38+
// #enddocregion hooks
39+
constructor(private _logger:LoggerService){
40+
this._logIt('AfterContent constructor');
4841
}
4942

50-
ngAfterViewInit() {
51-
this._logger.log(`AfterViewInit: There is ${this.viewChild ? 'a' : 'no'} view child`);
43+
// #docregion hooks
44+
ngAfterContentInit() {
45+
// viewChild is set after the view has been initialized
46+
this._logIt('AfterContentInit');
47+
this._doSomething();
5248
}
5349

54-
private _prevHero:string;
5550
ngAfterContentChecked() {
56-
// contentChild is updated after the content has been checked
57-
// Called frequently; only report when the hero changes
58-
if (!this.contentChild || this._prevHero === this.contentChild.hero) {return;}
59-
this._prevHero = this.contentChild.hero;
60-
this._logger.log('AfterContentChecked: ' + this._getMessage());
51+
// viewChild is updated after the view has been checked
52+
if (this._prevHero === this.contentChild.hero) {
53+
this._logIt('AfterContentChecked (no change)');
54+
} else {
55+
this._prevHero = this.contentChild.hero;
56+
this._logIt('AfterContentChecked');
57+
this._doSomething();
58+
}
6159
}
60+
// #enddocregion hooks
6261

63-
private _getMessage(): string {
64-
let cmp = this.contentChild;
65-
return cmp ? `"${cmp.hero}" child content` : 'no child content';
62+
comment = '';
63+
64+
// #docregion do-something
65+
66+
// This surrogate for real business logic sets the `comment`
67+
private _doSomething() {
68+
this.comment = this.contentChild.hero.length > 10 ? "That's a long name" : '';
6669
}
6770

71+
private _logIt(method:string){
72+
let vc = this.contentChild;
73+
let message = `${method}: ${vc ? vc.hero:'no'} child view`
74+
this._logger.log(message);
75+
}
76+
// #docregion hooks
77+
// ...
6878
}
79+
// #enddocregion hooks
6980

70-
/***************************************/
71-
81+
//////////////
7282
@Component({
7383
selector: 'after-content-parent',
7484
template: `
7585
<div class="parent">
7686
<h2>AfterContent</h2>
7787
78-
<after-content>
79-
<input [(ngModel)]="hero">
80-
<button (click)="showChild = !showChild">Toggle child view</button>
81-
82-
<my-child *ngIf="showChild" [hero]="hero"></my-child>
83-
</after-content>
84-
85-
<h4>-- Lifecycle Hook Log --</h4>
86-
<div *ngFor="#msg of hookLog">{{msg}}</div>
88+
<div *ngIf="show">` +
89+
// #docregion parent-template
90+
`<after-content>
91+
<my-child></my-child>
92+
</after-content>`
93+
// #enddocregion parent-template
94+
+ `</div>
95+
96+
<h4>-- AfterContent Logs --</h4>
97+
<p><button (click)="reset()">Reset</button></p>
98+
<div *ngFor="#msg of logs">{{msg}}</div>
8799
</div>
88100
`,
89-
styles: ['.parent {background: powderblue; padding: 8px; margin:100px 8px;}'],
90-
directives: [AfterContentComponent, ChildComponent],
91-
providers:[LoggerService]
101+
styles: ['.parent {background: burlywood}'],
102+
providers:[LoggerService],
103+
directives: [AfterContentComponent, ChildComponent]
92104
})
93105
export class AfterContentParentComponent {
94-
95-
hookLog:string[];
96-
hero = 'Magneta';
97-
showChild = true;
106+
logs:string[];
107+
show = true;
98108

99109
constructor(logger:LoggerService){
100-
this.hookLog = logger.logs;
110+
this.logs = logger.logs;
111+
}
112+
113+
reset() {
114+
this.logs.length=0;
115+
// quickly remove and reload AfterContentComponent which recreates it
116+
this.show = false;
117+
setTimeout(() => this.show = true, 0)
101118
}
102119
}

0 commit comments

Comments
 (0)