访问 'this' 内部承诺

Access 'this' Inside Promise

在下面的打字稿函数中,'this' 没有解析为 EmailValidator 的实例。我如何更正此函数,使其解析为正确的 EmailVaildator 实例,然后我才能访问 _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;
    }
}

原来'this'引用是未定义的,即使它被如下使用:

class EmailValidator {

    constructor(private _registerServices: RegisterServices) { }

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

我认为这与方法的调用方式有关,可能是在需要静态方法的地方传递了一个非静态方法:

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

如果有人可以就这里发生的事情提供一些指导,那就太好了。

我的解决方案

我重新排序了我的代码并生成了以下内容:

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;
    }
}

并修改了它的用法:

...
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,因为你在此处将 isAvailableEmail 作为 "raw" 函数传递:

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

您可以通过将其绑定到 this(使用粗箭头)来解决此问题:

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

您遇到问题是因为您正在传递 isAvailable 的值,它是一个函数。您没有执行它,您只是将引用传递给函数。

一种解决方法如

另一种方法是将 isAvailable 分配给 lambda 表达式而不是函数。像这样:

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;
    }
}

我会提议写得有点不同

class EmailValidator {

    constructor(private _registerServices: RegisterServices) { }

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

        });

    }
}