Passing instance method in Angular2.
When calling login() from the template in the following code, I get this error:
Failure TypeError: Cannot read property 'router' of null
at AuthLoginComponent.success (auth-login.component.ts:30)
at ZoneDelegate.invoke (zone.js:242)
at Object.onInvoke (core.umd.js:4391)
at ZoneDelegate.invoke (zone.js:241)
at Zone.run (zone.js:113)
at zone.js:520
at ZoneDelegate.invokeTask (zone.js:275)
at Object.onInvokeTask (core.umd.js:4382)
at ZoneDelegate.invokeTask (zone.js:274)
at Zone.runTask (zone.js:151)
at drainMicroTaskQueue (zone.js:418)
at XMLHttpRequest.ZoneTask.invoke (zone.js:349)
In the following code:
@Component({
moduleId: module.id,
selector: "app-auth-login",
templateUrl: "/app/components/auth/login/auth-login.component.html"
})
export class AuthLoginComponent implements OnInit {
username : "";
password : "";
constructor(
private authLoginService: AuthLoginService,
private router: Router
) {}
ngOnInit(): void {
}
success(value: Response) : void {
console.log("Success", value);
this.router.navigate(["/home"]);
}
failure(value: Response) : void {
console.log("Failure", value);
}
login() : void {
this.authLoginService.login(
this.username,
this.password,
this.success,
this.failure
)
}
}
I have tried passing this and success and then calling t[success]() in the service, but this produces the exact same error.
My service implements a client side "load balancer" with the circuit breaker pattern, which is the reason why I pass the success/failure function to reuse my code as much as possible.
The service is using rxjs with toPromise, e.g.
httpService(...).toPromise().then(success).catch(response => {(circuit breaker pattern on some failures)})
You need to bind this, otherwise this within the callback will point to the caller.
login() : void {
this.authLoginService.login(
this.username,
this.password,
this.success.bind(this),
this.failure.bind(this)
)
}
an alternative way is to use arrow function
login() : void {
this.authLoginService.login(
this.username,
this.password,
(value) => this.success(value),
(value) => this.failure(value)
)
}
Methods that are supposed to be used as callbacks by design can be bound to the context on their definition. This way there's no chance that they will be accidentally passed without proper context.
This can be achieved with arrow:
success = (value: Response) : void => { ... }
Or by binding the method in constructor:
constructor(...) {
this.success = this.success.bind(this);
...
}
The second way has an advantage, it allows to spy/mock method as AuthLoginComponent.prototype.success.
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