From b696413a7991ee39dea475b64e9027a17dc61b92 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Tue, 23 Jul 2019 16:10:01 -0700 Subject: [PATCH] fix(ivy): support attribute selectors in dynamic component creation (#31812) This commit fixes a bug where we assumed all dynamically created components would have tag-name selectors, so we passed through the "tag name" to the renderer as the first index of the selector. For components with attribute selectors, the tag name would be "", so the renderer would try to create an element with tag name "" and throw. Now we default to a "div" element the same way that View Engine did. Closes #31785 PR Close #31812 --- packages/core/src/render3/component_ref.ts | 4 ++- .../acceptance/view_container_ref_spec.ts | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index a2f787db70..c049428499 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -113,7 +113,9 @@ export class ComponentFactory extends viewEngine_ComponentFactory { private componentDef: ComponentDef, private ngModule?: viewEngine_NgModuleRef) { super(); this.componentType = componentDef.type; - this.selector = componentDef.selectors[0][0] as string; + + // default to 'div' in case this component has an attribute selector + this.selector = componentDef.selectors[0][0] as string || 'div'; this.ngContentSelectors = componentDef.ngContentSelectors ? componentDef.ngContentSelectors : []; this.isBoundToModule = !!ngModule; diff --git a/packages/core/test/acceptance/view_container_ref_spec.ts b/packages/core/test/acceptance/view_container_ref_spec.ts index fdf6a8f74b..3eed859422 100644 --- a/packages/core/test/acceptance/view_container_ref_spec.ts +++ b/packages/core/test/acceptance/view_container_ref_spec.ts @@ -114,6 +114,41 @@ describe('ViewContainerRef', () => { expect(testParent.childNodes[1].textContent).toBe('hello'); } }); + + it('should support attribute selectors in dynamically created components', () => { + @Component({selector: '[hello]', template: 'Hello'}) + class HelloComp { + } + + @NgModule({entryComponents: [HelloComp], declarations: [HelloComp]}) + class HelloCompModule { + } + + @Component({ + template: ` + + ` + }) + class TestComp { + @ViewChild('container', {read: ViewContainerRef, static: false}) vcRef !: ViewContainerRef; + + constructor(public cfr: ComponentFactoryResolver) {} + + createComponent() { + const factory = this.cfr.resolveComponentFactory(HelloComp); + this.vcRef.createComponent(factory); + } + } + + TestBed.configureTestingModule({declarations: [TestComp], imports: [HelloCompModule]}); + const fixture = TestBed.createComponent(TestComp); + fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.innerHTML).not.toContain('Hello'); + + fixture.componentInstance.createComponent(); + fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.innerHTML).toContain('Hello'); + }); }); describe('insert', () => {