fix(ivy): call onChanges before onInit (#21793)

PR Close #21793
This commit is contained in:
Kara Erickson 2018-01-26 13:38:21 -08:00 committed by Jason Aden
parent d3d3f7191a
commit dcca799dbb
2 changed files with 31 additions and 7 deletions

View File

@ -99,16 +99,26 @@ export function NgOnChangesFeature<T>(type: Type<T>): (definition: DirectiveDef<
} }
}); });
} }
definition.doCheck = (function(delegateDoCheck) {
// If an onInit hook is defined, it will need to wrap the ngOnChanges call
// so the call order is changes-init-check in creation mode. In subsequent
// change detection runs, only the check wrapper will be called.
if (definition.onInit != null) {
definition.onInit = onChangesWrapper(definition.onInit);
}
definition.doCheck = onChangesWrapper(definition.doCheck);
function onChangesWrapper(delegateHook: (() => void) | null) {
return function(this: OnChangesExpando) { return function(this: OnChangesExpando) {
let simpleChanges = this[PRIVATE_PREFIX]; let simpleChanges = this[PRIVATE_PREFIX];
if (simpleChanges != null) { if (simpleChanges != null) {
this.ngOnChanges(simpleChanges); this.ngOnChanges(simpleChanges);
this[PRIVATE_PREFIX] = null; this[PRIVATE_PREFIX] = null;
} }
delegateDoCheck && delegateDoCheck.apply(this); delegateHook && delegateHook.apply(this);
}; };
})(proto.ngDoCheck); }
}; };
} }

View File

@ -270,6 +270,7 @@ describe('compiler specification', () => {
describe('lifecycle hooks', () => { describe('lifecycle hooks', () => {
let events: string[] = []; let events: string[] = [];
let simpleLayout: SimpleLayout;
beforeEach(() => { events = []; }); beforeEach(() => { events = []; });
@ -277,6 +278,8 @@ describe('compiler specification', () => {
class LifecycleComp { class LifecycleComp {
@Input() nameMin: string; @Input() nameMin: string;
ngOnChanges() { events.push('changes' + this.nameMin); }
ngOnInit() { events.push('init' + this.nameMin); } ngOnInit() { events.push('init' + this.nameMin); }
ngDoCheck() { events.push('check' + this.nameMin); } ngDoCheck() { events.push('check' + this.nameMin); }
@ -293,7 +296,8 @@ describe('compiler specification', () => {
tag: 'lifecycle-comp', tag: 'lifecycle-comp',
factory: () => new LifecycleComp(), factory: () => new LifecycleComp(),
template: function(ctx: any, cm: boolean) {}, template: function(ctx: any, cm: boolean) {},
inputs: {nameMin: 'name'} inputs: {nameMin: 'name'},
features: [r3.NgOnChangesFeature(LifecycleComp)]
}); });
} }
@ -311,7 +315,7 @@ describe('compiler specification', () => {
static ngComponentDef = r3.defineComponent({ static ngComponentDef = r3.defineComponent({
type: SimpleLayout, type: SimpleLayout,
tag: 'simple-layout', tag: 'simple-layout',
factory: () => new SimpleLayout(), factory: () => simpleLayout = new SimpleLayout(),
template: function(ctx: any, cm: boolean) { template: function(ctx: any, cm: boolean) {
if (cm) { if (cm) {
r3.E(0, LifecycleComp); r3.E(0, LifecycleComp);
@ -333,8 +337,18 @@ describe('compiler specification', () => {
expect(renderComp(SimpleLayout)) expect(renderComp(SimpleLayout))
.toEqual(`<lifecycle-comp></lifecycle-comp><lifecycle-comp></lifecycle-comp>`); .toEqual(`<lifecycle-comp></lifecycle-comp><lifecycle-comp></lifecycle-comp>`);
expect(events).toEqual([ expect(events).toEqual([
'init1', 'check1', 'init2', 'check2', 'content init1', 'content check1', 'content init2', 'changes1', 'init1', 'check1', 'changes2', 'init2', 'check2', 'content init1',
'content check2', 'view init1', 'view check1', 'view init2', 'view check2' 'content check1', 'content init2', 'content check2', 'view init1', 'view check1',
'view init2', 'view check2'
]);
events = [];
simpleLayout.name1 = '-one';
simpleLayout.name2 = '-two';
r3.detectChanges(simpleLayout);
expect(events).toEqual([
'changes-one', 'check-one', 'changes-two', 'check-two', 'content check-one',
'content check-two', 'view check-one', 'view check-two'
]); ]);
}); });