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:
JoostK 2019-04-22 12:48:06 +02:00 committed by Ben Lesh
parent 0bcb2320ba
commit 19dfadb717
2 changed files with 49 additions and 1 deletions

View File

@ -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 = {

View File

@ -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[] = [