diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 72cc43db36..2ccec4d013 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -18,11 +18,11 @@ import {Type} from '../type'; import {assertComponentType, assertDefined} from './assert'; import {LifecycleHooksFeature, createRootContext} from './component'; -import {adjustBlueprintForNewNode, baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderEmbeddedTemplate} from './instructions'; +import {adjustBlueprintForNewNode, baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, queueHostBindingForCheck, renderEmbeddedTemplate, setHostBindings} from './instructions'; import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition'; import {LElementNode, TNode, TNodeType} from './interfaces/node'; import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; -import {BINDING_INDEX, CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view'; +import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view'; import {RootViewRef, ViewRef} from './view_ref'; export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver { @@ -138,6 +138,9 @@ export class ComponentFactory extends viewEngine_ComponentFactory { // Create directive instance with factory() and store at index 0 in directives array component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef); + if (this.componentDef.hostBindings) { + queueHostBindingForCheck(0, this.componentDef.hostVars); + } rootContext.components.push(component); initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !); (elementNode.data as LViewData)[CONTEXT] = component; @@ -146,6 +149,8 @@ export class ComponentFactory extends viewEngine_ComponentFactory { // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref LifecycleHooksFeature(component, this.componentDef); + setHostBindings(rootView[TVIEW].hostBindings); + // Transform the arrays of native nodes into a LNode structure that can be consumed by the // projection instruction. This is needed to support the reprojection of these nodes. if (projectableNodes) { diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index c072115c5b..64876de9e8 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -1705,4 +1705,65 @@ describe('ViewContainerRef', () => { ]); }); }); + + describe('host bindings', () => { + + it('should support host bindings on dynamically created components', () => { + + @Component( + {selector: 'host-bindings', host: {'id': 'attribute', '[title]': 'title'}, template: ``}) + class HostBindingCmpt { + title = 'initial'; + + static ngComponentDef = defineComponent({ + type: HostBindingCmpt, + selectors: [['host-bindings']], + factory: () => new HostBindingCmpt(), + consts: 0, + vars: 0, + template: (rf: RenderFlags, cmp: HostBindingCmpt) => {}, + hostVars: 1, + attributes: ['id', 'attribute'], + hostBindings: function(dirIndex, elIndex) { + const cmptInstance = loadDirective(dirIndex); + elementProperty(elIndex, 'title', bind(cmptInstance.title)); + }, + }); + } + + @Component({ + template: ` + + ` + }) + class AppCmpt { + static ngComponentDef = defineComponent({ + type: AppCmpt, + selectors: [['app']], + factory: () => new AppCmpt(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, cmp: AppCmpt) => { + if (rf & RenderFlags.Create) { + template(0, null, 0, 0, null, ['vcref', '']); + } + }, + directives: [HostBindingCmpt, DirectiveWithVCRef] + }); + } + + const fixture = new ComponentFixture(AppCmpt); + expect(fixture.html).toBe(''); + + const componentRef = directiveInstance !.vcref.createComponent( + directiveInstance !.cfr.resolveComponentFactory(HostBindingCmpt)); + expect(fixture.html).toBe(''); + + + componentRef.instance.title = 'changed'; + fixture.update(); + expect(fixture.html).toBe(''); + }); + + }); });