In my template, I'm using some third party component which renders a stepper, where you can navigate between the steps:
<my-stepper step="{{ currentStep }}" steps-label="steps"
[stepChangeCallback]="stepChangeCallback">
<my-stepper-step>First</my-stepper-step>
<my-stepper-step>First</my-stepper-step>
<my-stepper-step>First</my-stepper-step>
</my-stepper>
and
export class HeaderComponent implements OnInit {
currentStep = 0;
stepChangeCallback(selectedStep) {
this.currentStep = selectedStep; // PROBLEM: this does not point to HeaderComponent
}
}
So I thought I could just generate a new function with a fixed this pointer:
getStepChangeCallbackFunction() {
return this.stepChangeCallback.bind(this);
}
and
[stepChangeCallback]="getStepChangeCallbackFunction()"
This does work, however, I see that the memory consumption is rising constantly and that the website will eventually crash the browser, since it constantly generates new function copies.
Is there any other solution?
As for me, the best option here is to use instance arrow function:
stepChangeCallback = (selectedStep) => {
...
}
You could use [stepChangeCallback]="stepChangeCallback.bind(this)" but it will also create a new function every change detection run.
Another option is to bind this in constructor.
export class HeaderComponent implements OnInit {
constructor() {
this.stepChangeCallback = this.stepChangeCallback.bind(this);
}
stepChangeCallback(selectedStep) {
...
}
}
In addition to @yurzui answer, I think there is an anti-pattern with my-stepper component. Instead of taking an function as an input and calling it within, you can dispatch an event from my-stepper on stepChange.
Here is how you can do it
@Component({
selector: 'my-stepper',
...
})
export class MyStepperComponent {
@Input()
stepChangeCallback; // <- currently you have this.
@Output() // instead of an input, just define this output.
stepChange: EventEmitter<any> = new EventEmitter();
onStepChange(selectedStep) {
// currently, you call this.stepChangeCallback and you need to check if it is defined
if (this.stepChangeCallback) {
this.stepChangeCallback(selectedStep);
}
// instead you can simply emit an event and do not care about who is listening
this.stepChange.emit(selectedStep);
}
}
Then your template would be like following and you would not need to use arrow function as well
<my-stepper step="{{ currentStep }}" steps-label="steps"
(stepChange)="stepChangeCallback($event)">
<my-stepper-step>First</my-stepper-step>
<my-stepper-step>First</my-stepper-step>
<my-stepper-step>First</my-stepper-step>
</my-stepper>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With