Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compiler): not generating update instructions for ng-template inside alternate namespaces #41669

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,62 @@ export declare class MyModule {
static ɵinj: i0.ɵɵInjectorDeclaration<MyModule>;
}

/****************************************************************************************************
* PARTIAL FILE: svg_embedded_view.js
****************************************************************************************************/
import { Component, NgModule } from '@angular/core';
import * as i0 from "@angular/core";
export class MyComponent {
constructor() {
this.condition = true;
}
}
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, selector: "my-component", ngImport: i0, template: `
<svg>
<ng-template [ngIf]="condition">
<text>Hello</text>
</ng-template>
</svg>
`, isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, decorators: [{
type: Component,
args: [{
selector: 'my-component',
template: `
<svg>
<ng-template [ngIf]="condition">
<text>Hello</text>
</ng-template>
</svg>
`
}]
}] });
export class MyModule {
}
MyModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
MyModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule, declarations: [MyComponent] });
MyModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyModule, decorators: [{
type: NgModule,
args: [{ declarations: [MyComponent] }]
}] });

/****************************************************************************************************
* PARTIAL FILE: svg_embedded_view.d.ts
****************************************************************************************************/
import * as i0 from "@angular/core";
export declare class MyComponent {
condition: boolean;
static ɵfac: i0.ɵɵFactoryDeclaration<MyComponent, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<MyComponent, "my-component", never, {}, {}, never, never>;
}
export declare class MyModule {
static ɵfac: i0.ɵɵFactoryDeclaration<MyModule, never>;
static ɵmod: i0.ɵɵNgModuleDeclaration<MyModule, [typeof MyComponent], never, never>;
static ɵinj: i0.ɵɵInjectorDeclaration<MyModule>;
}

/****************************************************************************************************
* PARTIAL FILE: mathml.js
****************************************************************************************************/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@
}
]
},
{
"description": "should handle SVG with an embedded ng-template",
"inputFiles": [
"svg_embedded_view.ts"
],
"expectations": [
{
"files": [
{
"expected": "svg_embedded_view_template.js",
"generated": "svg_embedded_view.js"
}
],
"failureMessage": "Incorrect template."
}
]
},
{
"description": "should handle MathML",
"inputFiles": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Component, NgModule} from '@angular/core';

@Component({
selector: 'my-component',
template: `
<svg>
<ng-template [ngIf]="condition">
<text>Hello</text>
</ng-template>
</svg>
`
})
export class MyComponent {
condition = true;
}

@NgModule({declarations: [MyComponent]})
export class MyModule {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function MyComponent__svg_ng_template_1_Template(rf, ctx) {
if (rf & 1) {
i0.ɵɵnamespaceSVG();
i0.ɵɵelementStart(0, "text");
i0.ɵɵtext(1, "Hello");
i0.ɵɵelementEnd();
}
}

// NOTE: AttributeMarker.Bindings = 3
consts: [[3, "ngIf"]],
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {
i0.ɵɵnamespaceSVG();
i0.ɵɵelementStart(0, "svg");
i0.ɵɵtemplate(1, MyComponent__svg_ng_template_1_Template, 2, 0, "ng-template", 0);
i0.ɵɵelementEnd();
}
if (rf & 2) {
i0.ɵɵadvance(1);
i0.ɵɵproperty("ngIf", ctx.condition);
}
}
12 changes: 6 additions & 6 deletions packages/compiler/src/render3/view/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -875,17 +875,17 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
this.i18n.appendTemplate(template.i18n!, templateIndex);
}

const tagName = sanitizeIdentifier(template.tagName || '');
const contextName = `${this.contextName}${tagName ? '_' + tagName : ''}_${templateIndex}`;
const tagNameWithoutNamespace =
template.tagName ? splitNsName(template.tagName)[1] : template.tagName;
const contextName = `${this.contextName}${
template.tagName ? '_' + sanitizeIdentifier(template.tagName) : ''}_${templateIndex}`;
const templateName = `${contextName}_Template`;

const parameters: o.Expression[] = [
o.literal(templateIndex),
o.variable(templateName),

// We don't care about the tag's namespace here, because we infer
// it based on the parent nodes inside the template instruction.
o.literal(template.tagName ? splitNsName(template.tagName)[1] : template.tagName),
o.literal(tagNameWithoutNamespace),
];

// find directives matching on a given <ng-template> node
Expand Down Expand Up @@ -937,7 +937,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
this.templatePropertyBindings(templateIndex, template.templateAttrs);

// Only add normal input/output binding instructions on explicit <ng-template> elements.
if (template.tagName === NG_TEMPLATE_TAG_NAME) {
if (tagNameWithoutNamespace === NG_TEMPLATE_TAG_NAME) {
const [i18nInputs, inputs] =
partitionArray<t.BoundAttribute, t.BoundAttribute>(template.inputs, hasI18nMeta);

Expand Down
21 changes: 21 additions & 0 deletions packages/core/test/acceptance/integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1990,6 +1990,27 @@ describe('acceptance integration tests', () => {
expect(logs).toEqual(['Baggins']);
});

it('should render SVG nodes placed inside ng-template', () => {
@Component({
template: `
<svg>
<ng-template [ngIf]="condition">
<text>Hello</text>
</ng-template>
</svg>
`,
})
class MyComp {
condition = true;
}

TestBed.configureTestingModule({declarations: [MyComp], imports: [CommonModule]});
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();

expect(fixture.nativeElement.innerHTML).toContain('<text>Hello</text>');
});

describe('tView.firstUpdatePass', () => {
function isFirstUpdatePass() {
const lView = getLView();
Expand Down