Skip to content

Commit 89cf62f

Browse files
JoostKthePunderWoman
authored andcommitted
fix(compiler-cli): only bind inputs that are part of microsyntax to a structural directive (#52453)
Prior to this change the template type-check generator would incorrectly apply inputs and attributes to a structural directive, where only the bindings as present in microsyntax are actually bound to the directive. This introduced a problem where usages of template variables could not be resolved, because the template variables are out-of-scope of the template element itself. Closes #49931 PR Close #52453
1 parent 420af0b commit 89cf62f

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,10 +3422,16 @@ function getBoundAttributes(
34223422
}
34233423
};
34243424

3425-
node.inputs.forEach(processAttribute);
3426-
node.attributes.forEach(processAttribute);
34273425
if (node instanceof TmplAstTemplate) {
3426+
if (node.tagName === 'ng-template') {
3427+
node.inputs.forEach(processAttribute);
3428+
node.attributes.forEach(processAttribute);
3429+
}
3430+
34283431
node.templateAttrs.forEach(processAttribute);
3432+
} else {
3433+
node.inputs.forEach(processAttribute);
3434+
node.attributes.forEach(processAttribute);
34293435
}
34303436

34313437
return boundInputs;

packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,50 @@ describe('type check blocks', () => {
456456
expect(block).not.toContain('NoReference');
457457
});
458458

459+
it('should not bind inputs outside of microsyntax to a structural directive', () => {
460+
const TEMPLATE = `
461+
<my-dir *ngFor="let foo of foos" [ngForTrackBy]="foo"></my-dir>
462+
`;
463+
const DIRECTIVES: TestDeclaration[] = [
464+
{
465+
type: 'directive',
466+
name: 'NgFor',
467+
selector: '[ngFor][ngForOf]',
468+
inputs: {ngForOf: 'ngForOf', ngForTrackBy: 'ngForTrackBy'},
469+
},
470+
{
471+
type: 'directive',
472+
name: 'MyDir',
473+
selector: 'my-dir',
474+
inputs: {ngForTrackBy: 'ngForTrackBy'},
475+
},
476+
];
477+
const block = tcb(TEMPLATE, DIRECTIVES);
478+
expect(block).toContain('var _t1 = null! as i0.NgFor');
479+
expect(block).toContain('_t1.ngForOf = (((this).foos))');
480+
expect(block).not.toContain('_t1.ngForTrackBy');
481+
expect(block).toContain('var _t4 = null! as i0.MyDir');
482+
expect(block).toContain('_t4.ngForTrackBy =');
483+
});
484+
485+
it('should bind inputs to a structural directive when used on ng-template', () => {
486+
const TEMPLATE = `
487+
<ng-template ngFor [ngForOf]="foos" let-foo [ngForTrackBy]="foo"></ng-template>
488+
`;
489+
const DIRECTIVES: TestDeclaration[] = [
490+
{
491+
type: 'directive',
492+
name: 'NgFor',
493+
selector: '[ngFor][ngForOf]',
494+
inputs: {ngForOf: 'ngForOf', ngForTrackBy: 'ngForTrackBy'},
495+
},
496+
];
497+
const block = tcb(TEMPLATE, DIRECTIVES);
498+
expect(block).toContain('var _t1 = null! as i0.NgFor');
499+
expect(block).toContain('_t1.ngForOf = (((this).foos))');
500+
expect(block).toContain('_t1.ngForTrackBy = (((this).foo))');
501+
});
502+
459503
it('should generate a forward element reference correctly', () => {
460504
const TEMPLATE = `
461505
{{ i.value }}

0 commit comments

Comments
 (0)