feat(core): added afterContentInit, afterViewInit, and afterViewChecked hooks
Closes #3897
This commit is contained in:
@ -284,13 +284,21 @@ class _DirectiveUpdating {
|
||||
directiveIndex: new DirectiveIndex(0, 0),
|
||||
callOnChanges: true,
|
||||
callDoCheck: true,
|
||||
callAfterContentChecked: true
|
||||
callOnInit: true,
|
||||
callAfterContentInit: true,
|
||||
callAfterContentChecked: true,
|
||||
callAfterViewInit: true,
|
||||
callAfterViewChecked: true
|
||||
}),
|
||||
new DirectiveRecord({
|
||||
directiveIndex: new DirectiveIndex(0, 1),
|
||||
callOnChanges: true,
|
||||
callDoCheck: true,
|
||||
callAfterContentChecked: true
|
||||
callOnInit: true,
|
||||
callAfterContentInit: true,
|
||||
callAfterContentChecked: true,
|
||||
callAfterViewInit: true,
|
||||
callAfterViewChecked: true
|
||||
})
|
||||
];
|
||||
|
||||
@ -298,7 +306,11 @@ class _DirectiveUpdating {
|
||||
directiveIndex: new DirectiveIndex(0, 0),
|
||||
callOnChanges: false,
|
||||
callDoCheck: false,
|
||||
callAfterContentChecked: false
|
||||
callOnInit: false,
|
||||
callAfterContentInit: false,
|
||||
callAfterContentChecked: false,
|
||||
callAfterViewInit: false,
|
||||
callAfterViewChecked: false
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,3 @@
|
||||
///<reference path="../../../src/core/change_detection/pipe_transform.ts"/>
|
||||
import {
|
||||
ddescribe,
|
||||
describe,
|
||||
@ -361,12 +360,18 @@ export function main() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should notify the dispatcher on all changes done', () => {
|
||||
it('should notify the dispatcher after content children have checked', () => {
|
||||
var val = _createChangeDetector('name', new Person('bob'));
|
||||
val.changeDetector.detectChanges();
|
||||
expect(val.dispatcher.afterContentCheckedCalled).toEqual(true);
|
||||
});
|
||||
|
||||
it('should notify the dispatcher after view children have been checked', () => {
|
||||
var val = _createChangeDetector('name', new Person('bob'));
|
||||
val.changeDetector.detectChanges();
|
||||
expect(val.dispatcher.afterViewCheckedCalled).toEqual(true);
|
||||
});
|
||||
|
||||
describe('updating directives', () => {
|
||||
var directive1;
|
||||
var directive2;
|
||||
@ -385,148 +390,309 @@ export function main() {
|
||||
expect(directive1.a).toEqual(42);
|
||||
});
|
||||
|
||||
describe('onChanges', () => {
|
||||
it('should notify the directive when a group of records changes', () => {
|
||||
var cd = _createWithoutHydrate('groupChanges').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
cd.detectChanges();
|
||||
expect(directive1.changes).toEqual({'a': 1, 'b': 2});
|
||||
expect(directive2.changes).toEqual({'a': 3});
|
||||
describe('lifecycle', () => {
|
||||
describe('onChanges', () => {
|
||||
it('should notify the directive when a group of records changes', () => {
|
||||
var cd = _createWithoutHydrate('groupChanges').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
cd.detectChanges();
|
||||
expect(directive1.changes).toEqual({'a': 1, 'b': 2});
|
||||
expect(directive2.changes).toEqual({'a': 3});
|
||||
});
|
||||
});
|
||||
|
||||
describe('doCheck', () => {
|
||||
it('should notify the directive when it is checked', () => {
|
||||
var cd = _createWithoutHydrate('directiveDoCheck').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.doCheckCalled).toBe(true);
|
||||
directive1.doCheckCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
expect(directive1.doCheckCalled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not call doCheck in detectNoChanges', () => {
|
||||
var cd = _createWithoutHydrate('directiveDoCheck').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.doCheckCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onInit', () => {
|
||||
it('should notify the directive after it has been checked the first time', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnInit').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(true);
|
||||
|
||||
directive1.onInitCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
|
||||
it('should not call onInit in detectNoChanges', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnInit').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterContentInit', () => {
|
||||
it('should be called after processing the content children', () => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentInitCalled).toBe(true);
|
||||
expect(directive2.afterContentInitCalled).toBe(true);
|
||||
|
||||
// reset directives
|
||||
directive1.afterContentInitCalled = false;
|
||||
directive2.afterContentInitCalled = false;
|
||||
|
||||
// Verify that checking should not call them.
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.afterContentInitCalled).toBe(false);
|
||||
expect(directive2.afterContentInitCalled).toBe(false);
|
||||
|
||||
// re-verify that changes should not call them
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentInitCalled).toBe(false);
|
||||
expect(directive2.afterContentInitCalled).toBe(false);
|
||||
});
|
||||
|
||||
it('should not be called when afterContentInit is false', () => {
|
||||
var cd = _createWithoutHydrate('noCallbacks').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentInitCalled).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterContentChecked', () => {
|
||||
it('should be called after processing all the children', () => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toBe(true);
|
||||
expect(directive2.afterContentCheckedCalled).toBe(true);
|
||||
|
||||
// reset directives
|
||||
directive1.afterContentCheckedCalled = false;
|
||||
directive2.afterContentCheckedCalled = false;
|
||||
|
||||
// Verify that checking should not call them.
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toBe(false);
|
||||
expect(directive2.afterContentCheckedCalled).toBe(false);
|
||||
|
||||
// re-verify that changes are still detected
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toBe(true);
|
||||
expect(directive2.afterContentCheckedCalled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not be called when afterContentChecked is false', () => {
|
||||
var cd = _createWithoutHydrate('noCallbacks').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toEqual(false);
|
||||
});
|
||||
|
||||
it('should be called in reverse order so the child is always notified before the parent',
|
||||
() => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
|
||||
var onChangesDoneCalls = [];
|
||||
var td1;
|
||||
td1 = new TestDirective(() => onChangesDoneCalls.push(td1));
|
||||
var td2;
|
||||
td2 = new TestDirective(() => onChangesDoneCalls.push(td2));
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([td1, td2], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(onChangesDoneCalls).toEqual([td2, td1]);
|
||||
});
|
||||
|
||||
it('should be called before processing view children', () => {
|
||||
var parent = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
var child = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
parent.addShadowDomChild(child);
|
||||
|
||||
var orderOfOperations = [];
|
||||
|
||||
var directiveInShadowDom;
|
||||
directiveInShadowDom =
|
||||
new TestDirective(() => { orderOfOperations.push(directiveInShadowDom); });
|
||||
var parentDirective;
|
||||
parentDirective =
|
||||
new TestDirective(() => { orderOfOperations.push(parentDirective); });
|
||||
|
||||
parent.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([parentDirective], []),
|
||||
null);
|
||||
child.hydrate(_DEFAULT_CONTEXT, null,
|
||||
new FakeDirectives([directiveInShadowDom], []), null);
|
||||
|
||||
parent.detectChanges();
|
||||
expect(orderOfOperations).toEqual([parentDirective, directiveInShadowDom]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('afterViewInit', () => {
|
||||
it('should be called after processing the view children', () => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterViewInitCalled).toBe(true);
|
||||
expect(directive2.afterViewInitCalled).toBe(true);
|
||||
|
||||
// reset directives
|
||||
directive1.afterViewInitCalled = false;
|
||||
directive2.afterViewInitCalled = false;
|
||||
|
||||
// Verify that checking should not call them.
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.afterViewInitCalled).toBe(false);
|
||||
expect(directive2.afterViewInitCalled).toBe(false);
|
||||
|
||||
// re-verify that changes should not call them
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterViewInitCalled).toBe(false);
|
||||
expect(directive2.afterViewInitCalled).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
it('should not be called when afterViewInit is false', () => {
|
||||
var cd = _createWithoutHydrate('noCallbacks').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterViewInitCalled).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterViewChecked', () => {
|
||||
it('should be called after processing the view children', () => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterViewCheckedCalled).toBe(true);
|
||||
expect(directive2.afterViewCheckedCalled).toBe(true);
|
||||
|
||||
// reset directives
|
||||
directive1.afterViewCheckedCalled = false;
|
||||
directive2.afterViewCheckedCalled = false;
|
||||
|
||||
// Verify that checking should not call them.
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.afterViewCheckedCalled).toBe(false);
|
||||
expect(directive2.afterViewCheckedCalled).toBe(false);
|
||||
|
||||
// re-verify that changes should call them
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterViewCheckedCalled).toBe(true);
|
||||
expect(directive2.afterViewCheckedCalled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not be called when afterViewChecked is false', () => {
|
||||
var cd = _createWithoutHydrate('noCallbacks').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterViewCheckedCalled).toEqual(false);
|
||||
});
|
||||
|
||||
it('should be called in reverse order so the child is always notified before the parent',
|
||||
() => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
|
||||
var onChangesDoneCalls = [];
|
||||
var td1;
|
||||
td1 = new TestDirective(null, () => onChangesDoneCalls.push(td1));
|
||||
var td2;
|
||||
td2 = new TestDirective(null, () => onChangesDoneCalls.push(td2));
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([td1, td2], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(onChangesDoneCalls).toEqual([td2, td1]);
|
||||
});
|
||||
|
||||
it('should be called after processing view children', () => {
|
||||
var parent = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
var child = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
parent.addShadowDomChild(child);
|
||||
|
||||
var orderOfOperations = [];
|
||||
|
||||
var directiveInShadowDom;
|
||||
directiveInShadowDom = new TestDirective(
|
||||
null, () => { orderOfOperations.push(directiveInShadowDom); });
|
||||
var parentDirective;
|
||||
parentDirective =
|
||||
new TestDirective(null, () => { orderOfOperations.push(parentDirective); });
|
||||
|
||||
parent.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([parentDirective], []),
|
||||
null);
|
||||
child.hydrate(_DEFAULT_CONTEXT, null,
|
||||
new FakeDirectives([directiveInShadowDom], []), null);
|
||||
|
||||
parent.detectChanges();
|
||||
expect(orderOfOperations).toEqual([directiveInShadowDom, parentDirective]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('doCheck', () => {
|
||||
it('should notify the directive when it is checked', () => {
|
||||
var cd = _createWithoutHydrate('directiveDoCheck').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.doCheckCalled).toBe(true);
|
||||
directive1.doCheckCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
expect(directive1.doCheckCalled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not call doCheck in detectNoChanges', () => {
|
||||
var cd = _createWithoutHydrate('directiveDoCheck').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.doCheckCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onInit', () => {
|
||||
it('should notify the directive after it has been checked the first time', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnInit').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(true);
|
||||
|
||||
directive1.onInitCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
|
||||
it('should not call onInit in detectNoChanges', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnInit').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterContentChecked', () => {
|
||||
it('should be called after processing all the children', () => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []),
|
||||
null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toBe(true);
|
||||
expect(directive2.afterContentCheckedCalled).toBe(true);
|
||||
|
||||
// reset directives
|
||||
directive1.afterContentCheckedCalled = false;
|
||||
directive2.afterContentCheckedCalled = false;
|
||||
|
||||
// Verify that checking should not call them.
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toBe(false);
|
||||
expect(directive2.afterContentCheckedCalled).toBe(false);
|
||||
|
||||
// re-verify that changes are still detected
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toBe(true);
|
||||
expect(directive2.afterContentCheckedCalled).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
it('should not be called when afterContentChecked is false', () => {
|
||||
var cd = _createWithoutHydrate('noCallbacks').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.afterContentCheckedCalled).toEqual(false);
|
||||
});
|
||||
|
||||
it('should be called in reverse order so the child is always notified before the parent',
|
||||
() => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
|
||||
var onChangesDoneCalls = [];
|
||||
var td1;
|
||||
td1 = new TestDirective(() => onChangesDoneCalls.push(td1));
|
||||
var td2;
|
||||
td2 = new TestDirective(() => onChangesDoneCalls.push(td2));
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([td1, td2], []), null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(onChangesDoneCalls).toEqual([td2, td1]);
|
||||
});
|
||||
|
||||
it('should be called before processing shadow dom children', () => {
|
||||
var parent = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
var child = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
parent.addShadowDomChild(child);
|
||||
|
||||
var orderOfOperations = [];
|
||||
|
||||
var directiveInShadowDom = null;
|
||||
directiveInShadowDom =
|
||||
new TestDirective(() => { orderOfOperations.push(directiveInShadowDom); });
|
||||
var parentDirective = null;
|
||||
parentDirective =
|
||||
new TestDirective(() => { orderOfOperations.push(parentDirective); });
|
||||
|
||||
parent.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([parentDirective], []),
|
||||
null);
|
||||
child.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directiveInShadowDom], []),
|
||||
null);
|
||||
|
||||
parent.detectChanges();
|
||||
expect(orderOfOperations).toEqual([parentDirective, directiveInShadowDom]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1104,21 +1270,17 @@ class TestDirective {
|
||||
a;
|
||||
b;
|
||||
changes;
|
||||
afterContentCheckedCalled;
|
||||
afterContentCheckedSpy;
|
||||
doCheckCalled;
|
||||
onInitCalled;
|
||||
doCheckCalled = false;
|
||||
onInitCalled = false;
|
||||
|
||||
afterContentInitCalled = false;
|
||||
afterContentCheckedCalled = false;
|
||||
|
||||
afterViewInitCalled = false;
|
||||
afterViewCheckedCalled = false;
|
||||
event;
|
||||
|
||||
constructor(onChangesDoneSpy = null) {
|
||||
this.afterContentCheckedCalled = false;
|
||||
this.doCheckCalled = false;
|
||||
this.onInitCalled = false;
|
||||
this.afterContentCheckedSpy = onChangesDoneSpy;
|
||||
this.a = null;
|
||||
this.b = null;
|
||||
this.changes = null;
|
||||
}
|
||||
constructor(public afterContentCheckedSpy = null, public afterViewCheckedSpy = null) {}
|
||||
|
||||
onEvent(event) { this.event = event; }
|
||||
|
||||
@ -1132,12 +1294,23 @@ class TestDirective {
|
||||
this.changes = r;
|
||||
}
|
||||
|
||||
afterContentInit() { this.afterContentInitCalled = true; }
|
||||
|
||||
afterContentChecked() {
|
||||
this.afterContentCheckedCalled = true;
|
||||
if (isPresent(this.afterContentCheckedSpy)) {
|
||||
this.afterContentCheckedSpy();
|
||||
}
|
||||
}
|
||||
|
||||
afterViewInit() { this.afterViewInitCalled = true; }
|
||||
|
||||
afterViewChecked() {
|
||||
this.afterViewCheckedCalled = true;
|
||||
if (isPresent(this.afterViewCheckedSpy)) {
|
||||
this.afterViewCheckedSpy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Person {
|
||||
@ -1183,6 +1356,7 @@ class TestDispatcher implements ChangeDispatcher {
|
||||
debugLog: string[];
|
||||
loggedValues: List<any>;
|
||||
afterContentCheckedCalled: boolean = false;
|
||||
afterViewCheckedCalled: boolean = false;
|
||||
|
||||
constructor() { this.clear(); }
|
||||
|
||||
@ -1201,6 +1375,7 @@ class TestDispatcher implements ChangeDispatcher {
|
||||
logBindingUpdate(target, value) { this.debugLog.push(`${target.name}=${this._asString(value)}`); }
|
||||
|
||||
notifyAfterContentChecked() { this.afterContentCheckedCalled = true; }
|
||||
notifyAfterViewChecked() { this.afterViewCheckedCalled = true; }
|
||||
|
||||
getDebugContext(a, b) { return null; }
|
||||
|
||||
|
@ -88,6 +88,25 @@ main() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentInit", () {
|
||||
it("should be true when the directive implements AfterContentInit", () {
|
||||
expect(
|
||||
metadata(DirectiveImplementingAfterContentInit, new Directive())
|
||||
.callAfterContentInit).toBe(true);
|
||||
});
|
||||
|
||||
it("should be true when the lifecycle includes afterContentInit", () {
|
||||
expect(metadata(DirectiveNoHooks,
|
||||
new Directive(lifecycle: [LifecycleEvent.AfterContentInit]))
|
||||
.callAfterContentInit).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive())
|
||||
.callAfterContentInit).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentChecked", () {
|
||||
it("should be true when the directive implements AfterContentChecked", () {
|
||||
expect(
|
||||
@ -106,6 +125,44 @@ main() {
|
||||
.callAfterContentChecked).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterViewInit", () {
|
||||
it("should be true when the directive implements AfterViewInit", () {
|
||||
expect(
|
||||
metadata(DirectiveImplementingAfterViewInit, new Directive())
|
||||
.callAfterViewInit).toBe(true);
|
||||
});
|
||||
|
||||
it("should be true when the lifecycle includes afterViewInit", () {
|
||||
expect(metadata(DirectiveNoHooks,
|
||||
new Directive(lifecycle: [LifecycleEvent.AfterViewInit]))
|
||||
.callAfterViewInit).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive())
|
||||
.callAfterViewInit).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterViewChecked", () {
|
||||
it("should be true when the directive implements AfterViewChecked", () {
|
||||
expect(
|
||||
metadata(DirectiveImplementingAfterViewChecked, new Directive())
|
||||
.callAfterViewChecked).toBe(true);
|
||||
});
|
||||
|
||||
it("should be true when the lifecycle includes afterViewChecked", () {
|
||||
expect(metadata(DirectiveNoHooks,
|
||||
new Directive(lifecycle: [LifecycleEvent.AfterViewChecked]))
|
||||
.callAfterViewChecked).toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () {
|
||||
expect(metadata(DirectiveNoHooks, new Directive())
|
||||
.callAfterViewChecked).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -128,6 +185,18 @@ class DirectiveImplementingOnDestroy implements OnDestroy {
|
||||
onDestroy() {}
|
||||
}
|
||||
|
||||
class DirectiveImplementingAfterContentInit implements AfterContentInit {
|
||||
afterContentInit() {}
|
||||
}
|
||||
|
||||
class DirectiveImplementingAfterContentChecked implements AfterContentChecked {
|
||||
afterContentChecked() {}
|
||||
}
|
||||
|
||||
class DirectiveImplementingAfterViewInit implements AfterViewInit {
|
||||
afterViewInit() {}
|
||||
}
|
||||
|
||||
class DirectiveImplementingAfterViewChecked implements AfterViewChecked {
|
||||
afterViewChecked() {}
|
||||
}
|
||||
|
@ -102,6 +102,26 @@ export function main() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentInit", () => {
|
||||
it("should be true when the directive has the afterContentInit method", () => {
|
||||
expect(metadata(DirectiveWithAfterContentInitMethod, new DirectiveMetadata({}))
|
||||
.callAfterContentInit)
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be true when the lifecycle includes afterContentInit", () => {
|
||||
expect(metadata(DirectiveNoHooks,
|
||||
new DirectiveMetadata({lifecycle: [LifecycleEvent.AfterContentInit]}))
|
||||
.callAfterContentInit)
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentInit)
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterContentChecked", () => {
|
||||
it("should be true when the directive has the afterContentChecked method", () => {
|
||||
expect(metadata(DirectiveWithAfterContentCheckedMethod, new DirectiveMetadata({}))
|
||||
@ -121,6 +141,46 @@ export function main() {
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("afterViewInit", () => {
|
||||
it("should be true when the directive has the afterViewInit method", () => {
|
||||
expect(metadata(DirectiveWithAfterViewInitMethod, new DirectiveMetadata({}))
|
||||
.callAfterViewInit)
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be true when the lifecycle includes afterViewInit", () => {
|
||||
expect(metadata(DirectiveNoHooks,
|
||||
new DirectiveMetadata({lifecycle: [LifecycleEvent.AfterViewInit]}))
|
||||
.callAfterViewInit)
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewInit).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afterViewChecked", () => {
|
||||
it("should be true when the directive has the afterViewChecked method", () => {
|
||||
expect(metadata(DirectiveWithAfterViewCheckedMethod, new DirectiveMetadata({}))
|
||||
.callAfterViewChecked)
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be true when the lifecycle includes afterViewChecked", () => {
|
||||
expect(metadata(DirectiveNoHooks,
|
||||
new DirectiveMetadata({lifecycle: [LifecycleEvent.AfterViewChecked]}))
|
||||
.callAfterViewChecked)
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it("should be false otherwise", () => {
|
||||
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewChecked)
|
||||
.toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -143,6 +203,18 @@ class DirectiveWithOnDestroyMethod {
|
||||
onDestroy(_) {}
|
||||
}
|
||||
|
||||
class DirectiveWithAfterContentInitMethod {
|
||||
afterContentInit() {}
|
||||
}
|
||||
|
||||
class DirectiveWithAfterContentCheckedMethod {
|
||||
afterContentChecked() {}
|
||||
}
|
||||
|
||||
class DirectiveWithAfterViewInitMethod {
|
||||
afterViewInit() {}
|
||||
}
|
||||
|
||||
class DirectiveWithAfterViewCheckedMethod {
|
||||
afterViewChecked() {}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
it,
|
||||
xdescribe,
|
||||
xit,
|
||||
Log,
|
||||
TestComponentBuilder
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
@ -18,28 +19,26 @@ export function main() {
|
||||
describe('directive lifecycle integration spec', () => {
|
||||
|
||||
it('should invoke lifecycle methods onChanges > onInit > doCheck > afterContentChecked',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
inject([TestComponentBuilder, Log, AsyncTestCompleter], (tcb: TestComponentBuilder, log: Log,
|
||||
async) => {
|
||||
tcb.overrideView(
|
||||
MyComp,
|
||||
new ViewMetadata(
|
||||
{template: '<div [field]="123" lifecycle></div>', directives: [LifecycleDir]}))
|
||||
{template: '<div [field]="123" lifecycle></div>', directives: [LifecycleCmp]}))
|
||||
.createAsync(MyComp)
|
||||
.then((tc) => {
|
||||
var dir = tc.componentViewChildren[0].inject(LifecycleDir);
|
||||
tc.detectChanges();
|
||||
|
||||
expect(dir.log).toEqual(["onChanges", "onInit", "doCheck", "afterContentChecked"]);
|
||||
expect(log.result())
|
||||
.toEqual(
|
||||
"onChanges; onInit; doCheck; afterContentInit; afterContentChecked; child_doCheck; " +
|
||||
"afterViewInit; afterViewChecked");
|
||||
|
||||
log.clear();
|
||||
tc.detectChanges();
|
||||
|
||||
expect(dir.log).toEqual([
|
||||
"onChanges",
|
||||
"onInit",
|
||||
"doCheck",
|
||||
"afterContentChecked",
|
||||
"doCheck",
|
||||
"afterContentChecked"
|
||||
]);
|
||||
expect(log.result())
|
||||
.toEqual("doCheck; afterContentChecked; child_doCheck; afterViewChecked");
|
||||
|
||||
async.done();
|
||||
});
|
||||
@ -48,29 +47,43 @@ export function main() {
|
||||
}
|
||||
|
||||
|
||||
@Directive({
|
||||
@Directive({selector: '[lifecycle-dir]', lifecycle: [LifecycleEvent.DoCheck]})
|
||||
class LifecycleDir {
|
||||
constructor(private log: Log) {}
|
||||
doCheck() { this.log.add("child_doCheck"); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "[lifecycle]",
|
||||
properties: ['field'],
|
||||
lifecycle: [
|
||||
LifecycleEvent.OnChanges,
|
||||
LifecycleEvent.DoCheck,
|
||||
LifecycleEvent.OnInit,
|
||||
LifecycleEvent.AfterContentChecked
|
||||
LifecycleEvent.DoCheck,
|
||||
LifecycleEvent.AfterContentInit,
|
||||
LifecycleEvent.AfterContentChecked,
|
||||
LifecycleEvent.AfterViewInit,
|
||||
LifecycleEvent.AfterViewChecked
|
||||
]
|
||||
})
|
||||
class LifecycleDir {
|
||||
@View({template: `<div lifecycle-dir></div>`, directives: [LifecycleDir]})
|
||||
class LifecycleCmp {
|
||||
field;
|
||||
log: List<string>;
|
||||
constructor(private log: Log) {}
|
||||
|
||||
constructor() { this.log = []; }
|
||||
onChanges(_) { this.log.add("onChanges"); }
|
||||
|
||||
onChanges(_) { this.log.push("onChanges"); }
|
||||
onInit() { this.log.add("onInit"); }
|
||||
|
||||
onInit() { this.log.push("onInit"); }
|
||||
doCheck() { this.log.add("doCheck"); }
|
||||
|
||||
doCheck() { this.log.push("doCheck"); }
|
||||
afterContentInit() { this.log.add("afterContentInit"); }
|
||||
|
||||
afterContentChecked() { this.log.push("afterContentChecked"); }
|
||||
afterContentChecked() { this.log.add("afterContentChecked"); }
|
||||
|
||||
afterViewInit() { this.log.add("afterViewInit"); }
|
||||
|
||||
afterViewChecked() { this.log.add("afterViewChecked"); }
|
||||
}
|
||||
|
||||
@Component({selector: 'my-comp'})
|
||||
|
Reference in New Issue
Block a user