From b00038c847c67ff359d35878963915ab4f3eaee1 Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Wed, 22 Aug 2018 17:18:03 +0200 Subject: [PATCH] fix(ivy): inject ViewContainerRef for directives on ng-container (#25617) PR Close #25617 --- packages/core/src/render3/di.ts | 3 +- packages/core/src/render3/node_assert.ts | 5 +- .../test/render3/common_integration_spec.ts | 47 ++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index f59afc3726..1db254ca4b 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -586,7 +586,8 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer if (!di.viewContainerRef) { const vcRefHost = di.node; - ngDevMode && assertNodeOfPossibleTypes(vcRefHost, TNodeType.Container, TNodeType.Element); + ngDevMode && assertNodeOfPossibleTypes( + vcRefHost, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer); const hostParent = getParentLNode(vcRefHost) !; const lContainer = createLContainer(hostParent, vcRefHost.view, true); const comment = vcRefHost.view[RENDERER].createComment(ngDevMode ? 'container' : ''); diff --git a/packages/core/src/render3/node_assert.ts b/packages/core/src/render3/node_assert.ts index c30a0f2455..a4e1d991df 100644 --- a/packages/core/src/render3/node_assert.ts +++ b/packages/core/src/render3/node_assert.ts @@ -17,7 +17,9 @@ export function assertNodeType(node: LNode, type: TNodeType) { export function assertNodeOfPossibleTypes(node: LNode, ...types: TNodeType[]) { assertDefined(node, 'should be called with a node'); const found = types.some(type => node.tNode.type === type); - assertEqual(found, true, `Should be one of ${types.map(typeName).join(', ')}`); + assertEqual( + found, true, + `Should be one of ${types.map(typeName).join(', ')} but got ${typeName(node.tNode.type)}`); } function typeName(type: TNodeType): string { @@ -25,5 +27,6 @@ function typeName(type: TNodeType): string { if (type == TNodeType.Container) return 'Container'; if (type == TNodeType.View) return 'View'; if (type == TNodeType.Element) return 'Element'; + if (type == TNodeType.ElementContainer) return 'ElementContainer'; return ''; } diff --git a/packages/core/test/render3/common_integration_spec.ts b/packages/core/test/render3/common_integration_spec.ts index 8796872d98..faf7f88469 100644 --- a/packages/core/test/render3/common_integration_spec.ts +++ b/packages/core/test/render3/common_integration_spec.ts @@ -9,7 +9,7 @@ import {NgForOfContext} from '@angular/common'; import {AttributeMarker, defineComponent, templateRefExtractor} from '../../src/render3/index'; -import {bind, template, elementEnd, elementProperty, elementStart, getCurrentView, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, restoreView, text, textBinding} from '../../src/render3/instructions'; +import {bind, template, elementEnd, elementProperty, elementStart, getCurrentView, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, restoreView, text, textBinding, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def'; @@ -924,5 +924,50 @@ describe('@angular/common integration', () => { expect(fixture.html).toEqual(''); }); + it('should allow usage on ng-container', () => { + class MyApp { + showing = false; + static ngComponentDef = defineComponent({ + type: MyApp, + factory: () => new MyApp(), + selectors: [['my-app']], + consts: 3, + vars: 1, + /** + * from tpl + * + */ + template: (rf: RenderFlags, myApp: MyApp) => { + if (rf & RenderFlags.Create) { + template(0, (rf1: RenderFlags) => { + if (rf1 & RenderFlags.Create) { + text(0, 'from tpl'); + } + }, 1, 0, undefined, undefined, ['tpl', ''], templateRefExtractor); + elementContainerStart(2, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']); + elementContainerEnd(); + } + if (rf & RenderFlags.Update) { + const tplRef = load(1); + elementProperty(2, 'ngTemplateOutlet', bind(myApp.showing ? tplRef : null)); + } + }, + directives: () => [NgTemplateOutlet] + }); + } + + const fixture = new ComponentFixture(MyApp); + expect(fixture.html).toEqual(''); + + fixture.component.showing = true; + fixture.update(); + expect(fixture.html).toEqual('from tpl'); + + fixture.component.showing = false; + fixture.update(); + expect(fixture.html).toEqual(''); + + }); + }); });