Skip to content

Commit 2b7bad5

Browse files
crisbetodylhunn
authored andcommitted
fix(compiler): invoke method-based tracking function with context (#54960)
Previously we assumed that if a `for` loop tracking function is in the form of `someMethod($index, $item)`, it will be pure so we didn't pass the parameter to bind the context to it. This appears to be risky, because we don't know if the method is trying to access `this`. These changes play it safe by always binding method-based tracking functions. Fixes #53628. PR Close #54960
1 parent 78d4ad2 commit 2b7bad5

File tree

4 files changed

+26
-2
lines changed

4 files changed

+26
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
$r3$.ɵɵrepeaterCreate(0, MyApp_ng_template_2_For_1_Template, 0, 0, null, null, $r3$.ɵɵcomponentInstance().trackFn);
1+
$r3$.ɵɵrepeaterCreate(0, MyApp_ng_template_2_For_1_Template, 0, 0, null, null, $r3$.ɵɵcomponentInstance().trackFn, true);
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
$r3$.ɵɵrepeaterCreate(2, MyApp_For_3_Template, 0, 0, null, null, ctx.trackFn);
1+
$r3$.ɵɵrepeaterCreate(2, MyApp_For_3_Template, 0, 0, null, null, ctx.trackFn, true);

packages/compiler/src/template/pipeline/src/phases/track_fn_optimization.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ export function optimizeTrackFns(job: CompilationJob): void {
3131
// Top-level access of the item uses the built in `repeaterTrackByIdentity`.
3232
op.trackByFn = o.importExpr(Identifiers.repeaterTrackByIdentity);
3333
} else if (isTrackByFunctionCall(job.root.xref, op.track)) {
34+
// Mark the function as using the component instance to play it safe
35+
// since the method might be using `this` internally (see #53628).
36+
op.usesComponentInstance = true;
37+
3438
// Top-level method calls in the form of `fn($index, item)` can be passed in directly.
3539
if (op.track.receiver.receiver.view === unit.xref) {
3640
// TODO: this may be wrong

packages/core/test/acceptance/control_flow_for_spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,26 @@ describe('control flow - for', () => {
235235
fixture.detectChanges();
236236
expect([...calls].sort()).toEqual(['a:hello', 'b:hello']);
237237
});
238+
239+
it('should invoke method tracking function with the correct context', () => {
240+
let context = null as TestComponent | null;
241+
242+
@Component({
243+
template: `@for (item of items; track trackingFn($index, item)) {{{item}}}`,
244+
})
245+
class TestComponent {
246+
items = ['a', 'b'];
247+
248+
trackingFn(_index: number, item: string) {
249+
context = this;
250+
return item;
251+
}
252+
}
253+
254+
const fixture = TestBed.createComponent(TestComponent);
255+
fixture.detectChanges();
256+
expect(context).toBe(fixture.componentInstance);
257+
});
238258
});
239259

240260
describe('list diffing and view operations', () => {

0 commit comments

Comments
 (0)