fix(ivy): inject ViewContainerRef for directives on ng-container (#25617)
PR Close #25617
This commit is contained in:
parent
18f129f536
commit
b00038c847
@ -586,7 +586,8 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
|
|||||||
if (!di.viewContainerRef) {
|
if (!di.viewContainerRef) {
|
||||||
const vcRefHost = di.node;
|
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 hostParent = getParentLNode(vcRefHost) !;
|
||||||
const lContainer = createLContainer(hostParent, vcRefHost.view, true);
|
const lContainer = createLContainer(hostParent, vcRefHost.view, true);
|
||||||
const comment = vcRefHost.view[RENDERER].createComment(ngDevMode ? 'container' : '');
|
const comment = vcRefHost.view[RENDERER].createComment(ngDevMode ? 'container' : '');
|
||||||
|
@ -17,7 +17,9 @@ export function assertNodeType(node: LNode, type: TNodeType) {
|
|||||||
export function assertNodeOfPossibleTypes(node: LNode, ...types: TNodeType[]) {
|
export function assertNodeOfPossibleTypes(node: LNode, ...types: TNodeType[]) {
|
||||||
assertDefined(node, 'should be called with a node');
|
assertDefined(node, 'should be called with a node');
|
||||||
const found = types.some(type => node.tNode.type === type);
|
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 {
|
function typeName(type: TNodeType): string {
|
||||||
@ -25,5 +27,6 @@ function typeName(type: TNodeType): string {
|
|||||||
if (type == TNodeType.Container) return 'Container';
|
if (type == TNodeType.Container) return 'Container';
|
||||||
if (type == TNodeType.View) return 'View';
|
if (type == TNodeType.View) return 'View';
|
||||||
if (type == TNodeType.Element) return 'Element';
|
if (type == TNodeType.Element) return 'Element';
|
||||||
|
if (type == TNodeType.ElementContainer) return 'ElementContainer';
|
||||||
return '<unknown>';
|
return '<unknown>';
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {NgForOfContext} from '@angular/common';
|
import {NgForOfContext} from '@angular/common';
|
||||||
|
|
||||||
import {AttributeMarker, defineComponent, templateRefExtractor} from '../../src/render3/index';
|
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 {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
|
|
||||||
import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
|
import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
|
||||||
@ -924,5 +924,50 @@ describe('@angular/common integration', () => {
|
|||||||
expect(fixture.html).toEqual('');
|
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,
|
||||||
|
/**
|
||||||
|
* <ng-template #tpl>from tpl</ng-template>
|
||||||
|
* <ng-container [ngTemplateOutlet]="showing ? tpl : null"></ng-container>
|
||||||
|
*/
|
||||||
|
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('');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user