Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access 'this' Inside Promise

In the typescript function below, 'this' doesn't resolve to the instance of EmailValidator. How can I correct this function so it resolves to the correct instance of EmailVaildator and in turn, so that I can 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;
    }
}
like image 767
Liam M Avatar asked May 18 '16 00:05

Liam M


People also ask

How do you access an object inside a Promise?

To resolve the promise, we called the then() method on the promise object. The function we passed to the then() method gets called with the resolved value as a parameter. We can access this value in the body of the function. Notice that we also used the catch() method.

How do you access the variable this inside then scope?

var a = this; one(). then(function () { console. log(a) }); Update: use an arrow function - they borrow the context ( this ) from their outer scope.

How do you handle Promise rejection?

If an error condition arises inside a promise, you “reject” the promise by calling the reject() function with an error. To handle a promise rejection, you pass a callback to the catch() function. This is a simple example, so catching the rejection is trivial.

How does Promise all work internally?

The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will fulfill when all of the input's promises have fulfilled, or if the input iterable contains no promises.


2 Answers

You are losing this, because you are passing around the isAvailableEmail as a "raw" function here:

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

You can fix this by binding it to this (using the fat arrow):

email: ['', Validators.required,
  (control) => { this._emailValidator.isAvailableEmail(control) }
]
like image 107
Thilo Avatar answered Sep 22 '22 07:09

Thilo


It turned out that the 'this' reference was undefined even if it was used as follows:

class EmailValidator {

    constructor(private _registerServices: RegisterServices) { }

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

I gather this has something to do with how the method was called, perhaps passing a non-static method where 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 offer some guidance on what's occurring here, that'd be fantastic.

My Solution

I reordered my code and produced the following:

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 => {
                        // Need to actually check the result.
                        resolve({ "emailtaken": true })
                    },
                    error => {
                        // Need to communicate the server error? Probably not.
                        resolve({ "servererror": true })
                    });
            });
        };

        return g;
    }
}

And amended its usage:

...
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]
    });
...

Which works correctly.

like image 28
Liam M Avatar answered Sep 21 '22 07:09

Liam M