diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts
index 3d2c023f1a..25ee3abd9a 100644
--- a/packages/core/src/render3/node_manipulation.ts
+++ b/packages/core/src/render3/node_manipulation.ts
@@ -708,6 +708,14 @@ export function appendProjectedNode(
for (let i = 0; i < views.length; i++) {
addRemoveViewFromContainer(node as LContainerNode, views[i], true, node.native);
}
+ } else if (node.tNode.type === TNodeType.ElementContainer) {
+ let ngContainerChild = getChildLNode(node as LElementContainerNode);
+ while (ngContainerChild) {
+ appendProjectedNode(
+ ngContainerChild as LElementNode | LElementContainerNode | LTextNode | LContainerNode,
+ currentParent, currentView, renderParent);
+ ngContainerChild = getNextLNode(ngContainerChild);
+ }
}
if (node.dynamicLContainerNode) {
node.dynamicLContainerNode.data[RENDER_PARENT] = renderParent;
diff --git a/packages/core/test/render3/content_spec.ts b/packages/core/test/render3/content_spec.ts
index d30e2e7df1..4d69183275 100644
--- a/packages/core/test/render3/content_spec.ts
+++ b/packages/core/test/render3/content_spec.ts
@@ -12,7 +12,7 @@ import {Input, TemplateRef, ViewContainerRef, ViewRef} from '../../src/core';
import {defineDirective} from '../../src/render3/definition';
import {injectTemplateRef, injectViewContainerRef} from '../../src/render3/di';
import {AttributeMarker, detectChanges} from '../../src/render3/index';
-import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, loadDirective, projection, projectionDef, text} from '../../src/render3/instructions';
+import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, loadDirective, projection, projectionDef, text} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgIf} from './common_with_def';
@@ -1167,6 +1167,92 @@ describe('content projection', () => {
'BeforeB
456
After');
});
+ it('should project ng-container at the content root', () => {
+
+ ``;
+ const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
+ if (rf & RenderFlags.Create) {
+ projectionDef();
+ projection(0);
+ }
+ });
+
+ `
+
+
+ content
+
+
+ `;
+ const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
+ if (rf & RenderFlags.Create) {
+ elementStart(0, 'child');
+ {
+ elementContainerStart(1);
+ {
+ elementContainerStart(2);
+ { text(3, 'content'); }
+ elementContainerEnd();
+ }
+ elementContainerEnd();
+ }
+ elementEnd();
+ }
+ }, [Child]);
+
+ const parent = renderComponent(Parent);
+ expect(toHtml(parent)).toEqual('content');
+ });
+
+ it('should re-project ng-container at the content root', () => {
+
+ ``;
+ const GrandChild = createComponent('grand-child', function(rf: RenderFlags, ctx: any) {
+ if (rf & RenderFlags.Create) {
+ projectionDef();
+ projection(0);
+ }
+ });
+
+ `
+
+ `;
+ const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
+ if (rf & RenderFlags.Create) {
+ projectionDef();
+ elementStart(0, 'grand-child');
+ { projection(1); }
+ elementEnd();
+ }
+ }, [GrandChild]);
+
+ `
+
+
+ content
+
+
+ `;
+ const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
+ if (rf & RenderFlags.Create) {
+ elementStart(0, 'child');
+ {
+ elementContainerStart(1);
+ {
+ elementContainerStart(2);
+ { text(3, 'content'); }
+ elementContainerEnd();
+ }
+ elementContainerEnd();
+ }
+ elementEnd();
+ }
+ }, [Child]);
+
+ const parent = renderComponent(Parent);
+ expect(toHtml(parent)).toEqual('content');
+ });
+
describe('with selectors', () => {
it('should project nodes using attribute selectors', () => {