Implement callback in Angular2/Typescript with a focus on utilizing the 'this' reference

Need help with passing an instance method in Angular2.

Upon calling the login() function from the template in the code below, I encounter 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)

Take a look at the code snippet below:

@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 experimented with passing this and success, then invoking t[success]() within the service, however, the same error persists.

My service incorporates a client-side "load balancer" alongside the circuit breaker pattern, explaining my need to pass the success/failure functions for optimal code reuse.

The service harnesses rxjs with toPromise, as shown here:

httpService(...).toPromise().then(success).catch(response => {(circuit breaker pattern on some failures)})

Answer №1

It is important to bind this in order to ensure that within the callback, this points to the correct caller.

login() : void {
    this.authLoginService.login(
        this.username,
        this.password,
        this.success.bind(this),
        this.failure.bind(this)
    )
}

Another approach is to utilize arrow functions

login() : void {
    this.authLoginService.login(
        this.username,
        this.password,
        (value) => this.success(value), 
        (value) => this.failure(value)
    )
}

Answer №2

Designing methods to be used as callbacks inherently suggests that they should be bound to a specific context from the start to avoid any potential mistakes in passing them without the appropriate context.

One way to achieve this is by using arrow functions:

success = (value: Response) : void => { ... }

Another approach is to bind the method within the constructor:

constructor(...) {
  this.success = this.success.bind(this);
  ...
}

The latter method offers an advantage as it enables the ability to spy/mock the method as

AuthLoginComponent.prototype.success
.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Modifying the appearance of a Component within a NavLink

I'm currently working on a navbar using NavLink from React-Router-Dom. It's fine to use the 'isActive' prop to style the active Link, but I'm stuck on how to style the subelements inside it. For more specific details, please take a ...

After using apt to install tsc, I find myself in a dilemma on how to either delete or upgrade it

After realizing I was missing Typescript on my server, I attempted to run the 'tsc' command. However, I received a message suggesting I use 'apt install tsc' instead. Without much thought, I executed the command. Normally, I would insta ...

Resolving Problems with Ion-Split-pane in the Latest Versions of Angular and Ionic

There seems to be a perplexing issue with the ion-split-pane element that I just can't wrap my head around. Once I remove the split-pane element, the router-outlet functions perfectly fine. The navigation is displayed after a successful login. The on ...

Testing an Angular service call

I am currently testing whether a button click will trigger a method call in the service. Here is an excerpt of the component content: ngOnInit() { try { //GET ALL ITEMS this.service.getAll().pipe(untilDestroyed(this)).subscribe((result) =& ...

I am having trouble getting Angular 6 to work with lowdb

I am currently in the process of developing an Electron app with Angular 6, utilizing lowdb as a local database. This is all very new to me and I am learning through trial and error. However, I seem to be encountering difficulty resolving the following er ...

An easy guide to displaying an HTML string in a DIV with Angular 6

I have a Angular 6 application that interacts with the python API. The API responds with HTML data that I want to display on my existing page within a specific div element. I have attempted various methods but have not been successful. Test.ts public myT ...

Guide to setting up identically named properties in Child container components

As I am still fairly new to React and its concepts, I may not be executing this correctly. Although the question might seem lengthy, I'll try my best to keep it simple. I have created a component for TableHead that extends some material-ui components ...

What sets apart the ? operator from incorporating undefined in the type declaration?

Can you explain the distinctions among these options? type A = {a?: string} type A = {a: string | undefined} type A = {a?: string | undefined} In what scenarios would one be preferred over the others? For more information, visit: https://github.com/mic ...

Utilizing a Material UI custom theme in React with Typescript: A step-by-step guide

Upon using the tool , I received a js file and a json file following the paths mentioned on the theme generator page: // src/ui/theme/index.js /* src/ui/theme/theme.json */ The files operate smoothly when left with the .js extension. However, when I attem ...

Every npm task results in an identical error, even the simple version check (npm -v). In contrast to previous inquiries, not one npm action is functioning

After installing Node version 12.13.0 on my Windows 10 system, I encountered an issue where all npm commands were throwing the following error: C:\Users\Jahangeer> npm -v evalmachine.<anonymous>:27 const { Math, Object } = prim ...

Typescript not flagging an error for an object being declared without a type

I am encountering an issue with my tsconfig.json file: { "compilerOptions": { "allowJs": true, "allowSyntheticDefaultImports": true, "baseUrl": "src", "isolatedModules": true, "jsx": "preserve", "esModuleInterop": true, "forc ...

Having trouble utilizing the Visual Studio Code debugger in an Express.js project that uses TypeScript

My package.json file is shown below: ` { "name": "crm-backend", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev" ...

What sets *ngTemplateOutlet apart from [ngTemplateOutlet]?

Here is a unique explanation that is not a duplicate of the answers provided in this post or the correct explanation of the asterisk operator found here. However, it does build on the information presented in those posts. The concept of *ngBeep as a conve ...

Leveraging React and TypeScript's capabilities to pass around arguments efficiently

As I integrate TypeScript into my application, I find myself at a juncture where I need to specify the following: { id, label, type, styles, ...props } Incorporating this structure into a component like the one below: const TestComponent = ({ id, label, t ...

NextJS and AWS Amplify collaboration for secure authentication routing

After hours of research, I'm struggling to navigate the authentication routing in NextJS combined with AWS Amplify. As a newcomer to NextJS, I want to implement a feature that disables the login/register page for users who are already logged in and pr ...

Transforming a cURL command into an HTTP POST request in Angular 2

I am struggling to convert this cURL command into an angular 2 post request curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: Basic cGJob2xlOmlJelVNR3o4" -H "Origin: http://localhost:4200/form" -H "Postman-Token: fbf7ed ...

Surprising Logging Quirks in Angular

I've encountered a perplexing issue in my Angular app where an array is logged before adding an element to it, yet the log shows the updated array with the added element. This array is then utilized in an HTML file with ngFor. component.ts file inter ...

Problem with jasmine unit testing in a firebase-integrated ionic/angular application

I am currently working on an app using the Ionic and Firebase frameworks, and I have encountered an issue while writing unit tests for it. The error message I received is: Cannot read property 'subscribe' of undefined This error occurs during t ...

Is there a way to locate all projects impacted by `nx`?

Currently, I am utilizing the nx tool to manage a mono repo specifically designed for typescript projects. The nx comes equipped with a command called affected, which allows me to focus solely on the changed project and any other projects that rely on it. ...

Saving a picture to your Ionic device

I am currently using the code snippet below to access the device's Photo Library. However, it is returning a base64 encoded string, which has left me feeling unsure of how to proceed with this information. My goal is to save the photo to the applicati ...