diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 9e70d21bff..e5f9b03178 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -78,11 +78,13 @@ export function refreshDescendantViews(viewData: LViewData, rf: RenderFlags | nu if (rf !== RenderFlags.Create) { const creationMode = getCreationMode(); const checkNoChangesMode = getCheckNoChangesMode(); - setHostBindings(tView, viewData); if (!checkNoChangesMode) { executeInitHooks(viewData, tView, creationMode); } + + setHostBindings(tView, viewData); + refreshDynamicEmbeddedViews(viewData); // Content query results must be refreshed before content hooks are called. diff --git a/packages/core/test/render3/host_binding_spec.ts b/packages/core/test/render3/host_binding_spec.ts index ae741c8161..aa4dd225c1 100644 --- a/packages/core/test/render3/host_binding_spec.ts +++ b/packages/core/test/render3/host_binding_spec.ts @@ -8,7 +8,7 @@ import {EventEmitter} from '@angular/core'; -import {AttributeMarker, defineComponent, template, defineDirective, ProvidersFeature} from '../../src/render3/index'; +import {AttributeMarker, defineComponent, template, defineDirective, ProvidersFeature, NgOnChangesFeature} from '../../src/render3/index'; import {bind, directiveInject, element, elementEnd, elementProperty, elementStart, load, text, textBinding} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {pureFunction1, pureFunction2} from '../../src/render3/pure_function'; @@ -218,6 +218,72 @@ describe('host bindings', () => { expect(hostBindingDiv.id).toEqual('bar'); }); + it('should support host bindings that rely on values from init hooks', () => { + class InitHookComp { + // @Input() + inputValue = ''; + + changesValue = ''; + initValue = ''; + checkValue = ''; + + ngOnChanges() { this.changesValue = 'changes'; } + + ngOnInit() { this.initValue = 'init'; } + + ngDoCheck() { this.checkValue = 'check'; } + + get value() { + return `${this.inputValue}-${this.changesValue}-${this.initValue}-${this.checkValue}`; + } + + static ngComponentDef = defineComponent({ + type: InitHookComp, + selectors: [['init-hook-comp']], + factory: () => new InitHookComp(), + template: (rf: RenderFlags, ctx: InitHookComp) => {}, + consts: 0, + vars: 0, + hostVars: 1, + features: [NgOnChangesFeature], + hostBindings: (dirIndex: number, elIndex: number) => { + const ctx = load(dirIndex) as InitHookComp; + elementProperty(elIndex, 'title', bind(ctx.value)); + }, + inputs: {inputValue: 'inputValue'} + }); + } + + /** */ + class App { + value = 'input'; + + static ngComponentDef = defineComponent({ + type: App, + selectors: [['app']], + factory: () => new App(), + template: (rf: RenderFlags, ctx: App) => { + if (rf & RenderFlags.Create) { + element(0, 'init-hook-comp'); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'inputValue', bind(ctx.value)); + } + }, + consts: 1, + vars: 1, + directives: [InitHookComp] + }); + } + + const fixture = new ComponentFixture(App); + const initHookComp = fixture.hostElement.querySelector('init-hook-comp') as HTMLElement; + expect(initHookComp.title).toEqual('input-changes-init-check'); + + fixture.component.value = 'input2'; + fixture.update(); + expect(initHookComp.title).toEqual('input2-changes-init-check'); + }); it('should support host bindings on second template pass', () => { /**
*/