diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
index d16705e225..7ef43a01fb 100644
--- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
@@ -1510,6 +1510,51 @@ describe('compiler compliance', () => {
result.source, SimpleComponentDefinition, 'Incorrect SimpleComponent definition');
});
+ it('should include parsed ngProjectAs selectors into template attrs', () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ selector: 'my-app',
+ template: '
'
+ })
+ export class MyApp {
+ show = true;
+ }
+ `
+ }
+ };
+
+ const SimpleComponentDefinition = `
+ MyApp.ɵcmp = i0.ɵɵdefineComponent({
+ type: MyApp,
+ selectors: [
+ ["my-app"]
+ ],
+ decls: 1,
+ vars: 1,
+ consts: [
+ ["ngProjectAs", ".someclass", ${AttributeMarker.Template}, "ngIf", ${AttributeMarker.ProjectAs}, ["", 8, "someclass"]],
+ ["ngProjectAs", ".someclass", ${AttributeMarker.ProjectAs}, ["", 8, "someclass"]]
+ ],
+ template: function MyApp_Template(rf, ctx) {
+ if (rf & 1) {
+ i0.ɵɵtemplate(0, MyApp_div_0_Template, 1, 0, "div", 0);
+ }
+ if (rf & 2) {
+ i0.ɵɵproperty("ngIf", ctx.show);
+ }
+ },
+ encapsulation: 2
+ });
+ `;
+
+ const result = compile(files, angularFiles);
+ expectEmit(result.source, SimpleComponentDefinition, 'Incorrect MyApp definition');
+ });
+
});
describe('queries', () => {
diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts
index 897957aec9..4fd45693bb 100644
--- a/packages/compiler/src/render3/view/template.ts
+++ b/packages/compiler/src/render3/view/template.ts
@@ -841,6 +841,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver
visitTemplate(template: t.Template) {
const NG_TEMPLATE_TAG_NAME = 'ng-template';
const templateIndex = this.allocateDataSlot();
+ let ngProjectAsAttr: t.TextAttribute|undefined;
if (this.i18n) {
this.i18n.appendTemplate(template.i18n !, templateIndex);
@@ -864,10 +865,15 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver
// prepare attributes parameter (including attributes used for directive matching)
const attrsExprs: o.Expression[] = [];
- template.attributes.forEach(
- (a: t.TextAttribute) => { attrsExprs.push(asLiteral(a.name), asLiteral(a.value)); });
+ template.attributes.forEach((attr: t.TextAttribute) => {
+ if (attr.name === NG_PROJECT_AS_ATTR_NAME) {
+ ngProjectAsAttr = attr;
+ }
+ attrsExprs.push(asLiteral(attr.name), asLiteral(attr.value));
+ });
attrsExprs.push(...this.prepareNonRenderAttrs(
- template.inputs, template.outputs, undefined, template.templateAttrs));
+ template.inputs, template.outputs, undefined, template.templateAttrs, undefined,
+ ngProjectAsAttr));
parameters.push(this.addAttrsToConsts(attrsExprs));
// local refs (ex.: )
diff --git a/packages/core/test/acceptance/content_spec.ts b/packages/core/test/acceptance/content_spec.ts
index 142a86fe9c..a064b2e00c 100644
--- a/packages/core/test/acceptance/content_spec.ts
+++ b/packages/core/test/acceptance/content_spec.ts
@@ -1165,6 +1165,53 @@ describe('projection', () => {
expect(fixture.nativeElement).toHaveText('inline()ng-template(onetwothree)');
});
+ it('should project template content with `ngProjectAs` defined', () => {
+ @Component({
+ selector: 'projector-app',
+ template: `
+ Projected
+
+
+
+ `,
+ })
+ class ProjectorApp {
+ }
+
+ @Component({
+ selector: 'root-comp',
+ template: `
+
+ as element
+ as attribute
+ as class
+
+ `,
+ })
+ class RootComp {
+ show = true;
+ }
+
+ TestBed.configureTestingModule({
+ declarations: [ProjectorApp, RootComp],
+ });
+ const fixture = TestBed.createComponent(RootComp);
+ fixture.detectChanges();
+
+ let content = fixture.nativeElement.textContent;
+ expect(content).toContain('as element');
+ expect(content).toContain('as attribute');
+ expect(content).toContain('as class');
+
+ fixture.componentInstance.show = false;
+ fixture.detectChanges();
+
+ content = fixture.nativeElement.textContent;
+ expect(content).not.toContain('as element');
+ expect(content).not.toContain('as attribute');
+ expect(content).not.toContain('as class');
+ });
+
describe('on containers', () => {
it('should work when matching attributes', () => {
let xDirectives = 0;