fix(ivy): include context name for template functions for `ng-content` (#30025)
Previously, a template's context name would only be included in an embedded template function if the element that the template was declared on has a tag name. This is generally true for elements, except for `ng-content` that does not have a tag name. By omitting the context name the compiler could introduce duplicate template function names, which would fail at runtime. This commit fixes the behavior by always including the context name in the template function's name, regardless of tag name. Resolves FW-1272 PR Close #30025
This commit is contained in:
parent
0bcb2320ba
commit
19dfadb717
|
@ -592,6 +592,54 @@ describe('compiler compliance: template', () => {
|
||||||
expect(allTemplateFunctionsNames).toEqual(uniqueTemplateFunctionNames);
|
expect(allTemplateFunctionsNames).toEqual(uniqueTemplateFunctionNames);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create unique template function names for ng-content templates', () => {
|
||||||
|
const files = {
|
||||||
|
app: {
|
||||||
|
'spec.ts': `
|
||||||
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'a-component',
|
||||||
|
template: \`
|
||||||
|
<ng-content *ngIf="show"></ng-content>
|
||||||
|
\`,
|
||||||
|
})
|
||||||
|
export class AComponent {
|
||||||
|
show = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'b-component',
|
||||||
|
template: \`
|
||||||
|
<ng-content *ngIf="show"></ng-content>
|
||||||
|
\`,
|
||||||
|
})
|
||||||
|
export class BComponent {
|
||||||
|
show = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({declarations: [AComponent, BComponent]})
|
||||||
|
export class AModule {}
|
||||||
|
`
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = compile(files, angularFiles);
|
||||||
|
|
||||||
|
const allTemplateFunctionsNames = (result.source.match(/function ([^\s(]+)/g) || [])
|
||||||
|
.map(x => x.slice(9))
|
||||||
|
.filter(x => x.includes('Template'))
|
||||||
|
.sort();
|
||||||
|
const uniqueTemplateFunctionNames = Array.from(new Set(allTemplateFunctionsNames));
|
||||||
|
|
||||||
|
// Expected template function:
|
||||||
|
// - 1 for AComponent's template.
|
||||||
|
// - 1 for BComponent's template.
|
||||||
|
// - 2 for the two components.
|
||||||
|
expect(allTemplateFunctionsNames.length).toBe(1 + 1 + 2);
|
||||||
|
expect(allTemplateFunctionsNames).toEqual(uniqueTemplateFunctionNames);
|
||||||
|
});
|
||||||
|
|
||||||
it('should create unique listener function names even for similar nested template structures',
|
it('should create unique listener function names even for similar nested template structures',
|
||||||
() => {
|
() => {
|
||||||
const files = {
|
const files = {
|
||||||
|
|
|
@ -822,7 +822,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagName = sanitizeIdentifier(template.tagName || '');
|
const tagName = sanitizeIdentifier(template.tagName || '');
|
||||||
const contextName = `${tagName ? this.contextName + '_' + tagName : ''}_${templateIndex}`;
|
const contextName = `${this.contextName}${tagName ? '_' + tagName : ''}_${templateIndex}`;
|
||||||
const templateName = `${contextName}_Template`;
|
const templateName = `${contextName}_Template`;
|
||||||
|
|
||||||
const parameters: o.Expression[] = [
|
const parameters: o.Expression[] = [
|
||||||
|
|
Loading…
Reference in New Issue