【问题标题】:Access 'this' Inside Promise在 Promise 中访问“this”
【发布时间】:2016-05-18 00:32:17
【问题描述】:

在下面的打字稿函数中,'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;
    }
}

【问题讨论】:

  • 嗯。看起来胖箭头应该已经这样做了。并且查看生成的 Javascript,它似乎正确地别名为 this。你确定这是你看到的问题吗?
  • @Thilo 我后来发现问题有点隐藏,问题出在其他地方。我已经发现了如何纠正我的问题,但是有一些关于“为什么”问题发生的细节,我非常感谢一些指导。我会发布我的解决方案。

标签: typescript angular scoping


【解决方案1】:

您正在丢失this,因为您在这里将isAvailableEmail 作为“原始”函数传递:

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

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

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

【讨论】:

  • 谢谢蒂洛。我喜欢你的解决方案——这是最小的改变——但会坚持我的,因为它与 Angular 团队似乎已经实现了他们的验证器的方式是一致的。我会将您的答案作为已接受的答案,因为它最好地回答了原始问题。
  • 请注意,它们具有不需要配置的“静态”函数,例如 Validators.required,以及生成捕获所有配置的验证器函数的验证器工厂,例如 Validators.minLength(8)。您可以执行EmailValidator(registerServices) 之类的操作来生成一个捕获registerServices 并执行您的isAvailableEmail 操作的函数。
  • 因此,验证器不应该是一个类,而是一个创建另一个函数的函数(比如你的isAvailableEmail)。并且生成的函数是独立的。
【解决方案2】:

事实证明'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]
    });
...

哪个工作正常。

【讨论】:

    【解决方案3】:

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

    解决它的一种方法是@Thilo's answer

    另一种方法是将 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;
        }
    }
    

    【讨论】:

      【解决方案4】:

      我会提议写一点不同的

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

      【讨论】:

        猜你喜欢
        • 2016-12-12
        • 2016-03-26
        • 2015-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-13
        • 2020-08-29
        相关资源
        最近更新 更多