Skip to content

Commit b00038c

Browse files
pkozlowski-opensourcematsko
authored andcommitted
fix(ivy): inject ViewContainerRef for directives on ng-container (angular#25617)
PR Close angular#25617
1 parent 18f129f commit b00038c

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

packages/core/src/render3/di.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,8 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
586586
if (!di.viewContainerRef) {
587587
const vcRefHost = di.node;
588588

589-
ngDevMode && assertNodeOfPossibleTypes(vcRefHost, TNodeType.Container, TNodeType.Element);
589+
ngDevMode && assertNodeOfPossibleTypes(
590+
vcRefHost, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
590591
const hostParent = getParentLNode(vcRefHost) !;
591592
const lContainer = createLContainer(hostParent, vcRefHost.view, true);
592593
const comment = vcRefHost.view[RENDERER].createComment(ngDevMode ? 'container' : '');

packages/core/src/render3/node_assert.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ export function assertNodeType(node: LNode, type: TNodeType) {
1717
export function assertNodeOfPossibleTypes(node: LNode, ...types: TNodeType[]) {
1818
assertDefined(node, 'should be called with a node');
1919
const found = types.some(type => node.tNode.type === type);
20-
assertEqual(found, true, `Should be one of ${types.map(typeName).join(', ')}`);
20+
assertEqual(
21+
found, true,
22+
`Should be one of ${types.map(typeName).join(', ')} but got ${typeName(node.tNode.type)}`);
2123
}
2224

2325
function typeName(type: TNodeType): string {
2426
if (type == TNodeType.Projection) return 'Projection';
2527
if (type == TNodeType.Container) return 'Container';
2628
if (type == TNodeType.View) return 'View';
2729
if (type == TNodeType.Element) return 'Element';
30+
if (type == TNodeType.ElementContainer) return 'ElementContainer';
2831
return '<unknown>';
2932
}

packages/core/test/render3/common_integration_spec.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {NgForOfContext} from '@angular/common';
1010

1111
import {AttributeMarker, defineComponent, templateRefExtractor} from '../../src/render3/index';
12-
import {bind, template, elementEnd, elementProperty, elementStart, getCurrentView, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, restoreView, text, textBinding} from '../../src/render3/instructions';
12+
import {bind, template, elementEnd, elementProperty, elementStart, getCurrentView, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, restoreView, text, textBinding, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
1313
import {RenderFlags} from '../../src/render3/interfaces/definition';
1414

1515
import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
@@ -924,5 +924,50 @@ describe('@angular/common integration', () => {
924924
expect(fixture.html).toEqual('');
925925
});
926926

927+
it('should allow usage on ng-container', () => {
928+
class MyApp {
929+
showing = false;
930+
static ngComponentDef = defineComponent({
931+
type: MyApp,
932+
factory: () => new MyApp(),
933+
selectors: [['my-app']],
934+
consts: 3,
935+
vars: 1,
936+
/**
937+
* <ng-template #tpl>from tpl</ng-template>
938+
* <ng-container [ngTemplateOutlet]="showing ? tpl : null"></ng-container>
939+
*/
940+
template: (rf: RenderFlags, myApp: MyApp) => {
941+
if (rf & RenderFlags.Create) {
942+
template(0, (rf1: RenderFlags) => {
943+
if (rf1 & RenderFlags.Create) {
944+
text(0, 'from tpl');
945+
}
946+
}, 1, 0, undefined, undefined, ['tpl', ''], templateRefExtractor);
947+
elementContainerStart(2, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
948+
elementContainerEnd();
949+
}
950+
if (rf & RenderFlags.Update) {
951+
const tplRef = load(1);
952+
elementProperty(2, 'ngTemplateOutlet', bind(myApp.showing ? tplRef : null));
953+
}
954+
},
955+
directives: () => [NgTemplateOutlet]
956+
});
957+
}
958+
959+
const fixture = new ComponentFixture(MyApp);
960+
expect(fixture.html).toEqual('');
961+
962+
fixture.component.showing = true;
963+
fixture.update();
964+
expect(fixture.html).toEqual('from tpl');
965+
966+
fixture.component.showing = false;
967+
fixture.update();
968+
expect(fixture.html).toEqual('');
969+
970+
});
971+
927972
});
928973
});

0 commit comments

Comments
 (0)