Unlocking 'this' Within a Promise

I seem to have an issue with the 'this' reference in the typescript function provided. It is not correctly resolving to the instance of EmailValidator as expected. How can I fix this so that it points to the correct instance of EmailVaildator, allowing me to access _registerServices?

class EmailValidator {

    constructor(private _registerServices: RegisterServices) { }

    isAvailable(c: AbstractControl): Promise<ValidationResult> {
        let q = new Promise((resolve, reject) => {
            this._registerServices.emailIsAvailable(antiForgeryToken(), c.value)
                .then(result => {
                    // Need to actually check the result.
                    resolve({ "emailtaken": true })
                },
                error => {
                    // Need to communicate the server error? Probably not.
                    resolve({ "servererror": true })
                });
        });

        return q;
    }
}

Answer №1

You may be experiencing an issue with losing functionality due to how you are using isAvailableEmail as a "raw" function in this scenario:

email: ['', Validators.required, this._emailValidator.isAvailableEmail]

To resolve this, you should consider binding it to this by using the fat arrow syntax:

email: ['', Validators.required,
  (control) => { this._emailValidator.isAvailableEmail(control) }
]

Answer №2

Upon investigation, it was revealed that the 'this' reference turned out to be undefined even when used in the following context:

class EmailValidator {

    constructor(private _registerServices: RegisterServices) { }

    isAvailable(c: AbstractControl): EmailValidator {
        return this; // The 'This' reference is undefined!
    }
}

It seems that the issue might have stemmed from how the method was invoked, potentially involving passing a non-static method when a static method was expected:

...
this.registerForm = fb.group({
    email: ['', Validators.required, this._emailValidator.isAvailableEmail],
    password: ['', Validators.compose([Validators.required, Validators.minLength(8)])],
    phoneNumber: ['', Validators.required],
    country: ['', Validators.required]
    });
...

If someone could provide guidance on what exactly is happening here, it would be greatly appreciated.

Proposed Solution

To address the problem, I restructured my code and came up with the following solution:

class EmailValidator {

    static isAvailableEmail(services: RegisterServices): (AbstractControl) => Promise<ValidationResult> {
        let g = (c: AbstractControl) => {
            return new Promise((resolve, reject) => {
                services.emailIsAvailable(antiForgeryToken(), c.value)
                    .then(result => {
                        // Verification of the result is necessary.
                        resolve({ "emailtaken": true })
                    },
                    error => {
                        // Should server errors be communicated? Probably not.
                        resolve({ "servererror": true })
                    });
            });
        };

        return g;
    }
}

I made adjustments to its usage as well:

...
this.registerForm = fb.group({
    email: ['', Validators.required,
        EmailValidator.isAvailableEmail(this._registerService)],
    password: ['', Validators.compose([Validators.required, Validators.minLength(8)])],
    phoneNumber: ['', Validators.required],
    country: ['', Validators.required]
    });
...

This modification now functions correctly.

Answer №3

The issue you are experiencing arises from passing the value of isAvailable, which is a function, without executing it. Instead, you are simply passing a reference to the function.

To resolve this problem, one approach is highlighted in @Thilo's response

Another solution involves assigning isAvailable to a lambda expression rather than a traditional function. Here's how:

class EmailValidator {

    constructor(private _registerServices: RegisterServices) { }

    isAvailable = (c: AbstractControl): Promise<ValidationResult> => {
        let q = new Promise((resolve, reject) => {
            this._registerServices.emailIsAvailable(antiForgeryToken(), c.value)
                .then(result => {
                    // It is crucial to verify the result.
                    resolve({ "emailtaken": true })
                },
                error => {
                    // Should you relay the server error? Probably not necessary.
                    resolve({ "servererror": true })
                });
        });

        return q;
    }
}

Answer №4

I propose writing it in a slightly alternative manner

class EmailChecker {

    constructor(private _registrationServices: RegistrationServices) { }

    checkAvailability(emailControl: AbstractControl): Promise<ValidationResult> {
        return this._registrationServices.validateEmail(antiForgeryToken(), emailControl.value)
            .then(res => {
                // Make sure to verify the outcome.
                return { "emailExists": true }
            })
 // concise .then(res => ({ "emailExists": true }))
            .catch(err => {
                // Should we inform about server issues? Probably not necessary.
                return { "serverIssue": true }
            });
 // concise .catch(error => ({ "serverIssue": true }))

        });

    }
}

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

What is the best way to allocate string types from an enum using Typescript?

Within my code, I have an enum that includes a collection of strings export enum apiErrors { INVALID_SHAPE = "INVALID_SHAPE", NOT_FOUND = "NOT_FOUND", EXISTS = "EXISTS", INVALID_AUTH = "INVALID_AUTH", INTERNAL_SERVER_ERROR = "INTERNAL_ ...

Securing Your Angular 2 / ASP.NET MVC Application from CSRF Attacks

I am currently developing a single-page application using ASP.NET MVC for the backend and Angular 2 for the frontend. To prevent cross-site request forgery attacks in my application, I have implemented the following steps: Since ASP.NET MVC sends a co ...

Sharing functions between Angular components

Check out my problem statement: https://stackblitz.com/edit/angular-jk8dsj I'm facing two challenges with this assignment: I need to dynamically add elements in the app.component when clicking a button in the key-value.component. I've tried ...

What is the method for displaying script commands within package.json files?

With a multitude of repositories, each one unique in its setup, I find myself constantly referencing the package.json file to double-check the scripts. "scripts": { "start": "npm run dev" "build:dev": "N ...

Clicking on a single checkbox causes the entire input to become deactivated due to the way the system is

I'm encountering a puzzling issue that has me feeling like I know the solution, yet I don't. I set "State" to [checked]. The problem arises when, upon turning it into a map and clicking just one checkbox, the entire selection is clicked. To addre ...

What is the process for initiating an Angular 2 Materialize component?

I'm new to using angular2 materialize and I've found that the CSS components work perfectly fine. However, I'm facing an issue when it comes to initializing components like 'select'. I'm unsure of how or where to do this initi ...

Issue encountered with the inability to successfully subscribe to the LoggedIn Observable

After successfully logging in using a service in Angular, I am encountering an error while trying to hide the signin and signup links. The error message can be seen in this screenshot: https://i.stack.imgur.com/WcRYm.png Below is my service code snippet: ...

Modify the name of the document

I have a piece of code that retrieves a file from the clipboard and I need to change its name if it is named image.png. Below is the code snippet where I attempt to achieve this: @HostListener('paste', ['$event']) onPaste(e: ClipboardE ...

When incorporating a second overload as an object, it is generating a pair of errors

I'm currently working on creating an overload function that takes either two arguments or one argument as an object, which will be used in the following way: // Two parameters obj.set('a', '123'); obj.set('b', 'efg&a ...

What is the best way to guarantee an Array filled with Strings?

Which is the proper way to define a potentially array of strings? Promise<Array<string>> Or Promise<string[]> ...

The Angular library files built with ng build are not automatically included in the dist folder

My Angular 9 library has a project structure similar to the one shown below After running ng build falcon-core to build the library, I noticed that the view-model files are missing from the dist folder I couldn't find any settings in the tsconfig.li ...

There has been an unhandled runtime error: [object ProgressEvent] occurring with Next.js/Typescript

Exploring the world of nextJS and typescript is new to me. I am currently working on creating a simple blog using nextJS/typescript with a sanity CMS backend. Everything seems to be running smoothly during development, but then I encounter this Unhandled R ...

Issue with Angular drag and drop functionality arises when attempting to drop elements within an n-ary tree structure displayed using a recursive template

I am currently exploring the functionality of angular material drag and drop. Within my application, I have implemented an n-ary tree structure. Since the specific form of the tree is unknown beforehand, I have resorted to using a recursive template in or ...

Dealing with "Cannot find name" errors in Typescript when working with React components

I'm currently in the process of transitioning my React code to TypeScript, and I've encountered numerous challenges. One recurring issue is the "Cannot find name" errors that pop up when converting my .js files to .ts files. Let's take a lo ...

Incorporate a pair of functions within the (click) directive in Angular 5

I am trying to implement two functions that should execute on click <li class="active" (click)="routeTransaction(); activateClass(classChange)" *ngIf="permissionKeys.indexOf('TRANSACTIONS')>-1" [ngClass]="{'liactive': classChange ...

The HttpPut request code format is malfunctioning, although it is effective for another request

I'm struggling with a HTTPPUT request that just won't get called. Strangely enough, I have a similar put request that works perfectly fine for another tab even though both pages are practically identical. I've exhausted all options and can&a ...

Accessing Angular's Observable Objects

I am currently in the process of learning Angular and trying to work with Observables. However, I am facing an issue where I cannot extract data from an Observable when it is in object form. public rowData$!: Observable<any[]>; UpdateGrid() { this ...

What is the best way to securely store a JWT Token received from Cognito after logging in through the Cognito Hosted UI?

Our current architecture involves front end Angular and backend nodejs/express. This setup functions in the following order: User logs in to the site via Cognito Hosted UI Upon successful login, the user is redirected to our home page with a code sent in ...

Tips on integrating ActiveX controls in Angular

I built my project using Angular 6 and TypeScript in Visual Studio Code. The browser being used is IE11. Unfortunately, when I try to run the code written in app.component.html, it doesn't work as expected. The HTML code causing the issue is: <d ...

Working with Typescript to map and sort the key values of a new datasource object

Managing a large datasource filled with objects can be challenging. My goal is to rearrange the order of objects in the array based on new values for each key. Whenever a new value for a key is found, I want the corresponding object to move to the top of t ...