【问题标题】:Validate a form field asynchronously (after HTTP request) in Angular 2在Angular 2中异步验证表单字段(在HTTP请求之后)
【发布时间】:2017-01-26 19:20:11
【问题描述】:

这个想法是让用户发布表单。如果用户已经注册,则触发API返回的错误,将email字段设置为错误。

我在 FormBuilder 中使用反应式表单,并尝试在订阅错误捕获器中调用验证器:

构造函数:

this.email = fb.control('', [Validators.required, Validators.pattern(/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/), SignupComponent.alreadyExist()]);
this.username = fb.control('', [Validators.required, Validators.pattern(/^([A-ZÀ-ÿa-z0-9]{2,})+(?:[ _-][A-ZÀ-ÿa-z0-9]+)*$/)]);

this.userRegisterForm = fb.group({
    email: this.email,
    username: this.username
});

自定义 alreadyExist() 验证器:

static alreadyExist(alreadyExist: boolean = false): any {

    return (control: FormControl): { [s: string]: boolean } => {

        if(alreadyExist) {
            return { emailAlreadyExist: true }
        }
    }
}

onSubmit():

this.user.create(newUser)
    .subscribe(
        data => {
            this.router.navigate(['signin']);
        },
        error => {
            if(error.status === 401) {

                // CALL THE VALIDATOR HERE TO SET : FALSE
                SignupComponent.alreadyExist(true);
            }

            this.loading = false;
        });

似乎调用了验证器,但从未调用过其中返回的匿名方法......也许不是一个好习惯,任何人都可以突出显示我吗?谢谢

【问题讨论】:

    标签: angular typescript formbuilder customvalidator


    【解决方案1】:

    好的,我找到了一个很好的解决方案。

    就我而言,对于电子邮件 FormControl,我不需要自定义 validator(即使可以使用 setValidators())。

    我可以删除 alreadyExist() 并将其声明从 validators 列表中删除。

    然后,我使用 FormControl 上可用的 setErrors() 方法:

    onSubmit()

    this.user.create(newUser)
        .subscribe(
            data => {
                this.router.navigate(['signin']);
            },
            error => {
                if(error.status === 401) {
    
                    // CALL THE VALIDATOR HERE TO SET : FALSE
                    this.userRegisterForm.controls['email'].setErrors({
                      "emailAlreadyExist": true
                    });
                }
    
                this.loading = false;
            });
    

    电子邮件 FormControl 有一个新错误,因此,通过这种方式,我可以附加此错误的错误消息。

    【讨论】:

      【解决方案2】:

      哟凯文。 :) 如果我遵循,您当前的工作流程是:

      1. 让用户提交表单(以创建新帐户)。
      2. 如果创建新帐户失败,请手动将错误附加到表单中。

      不好。现在您可以在两个地方进行验证:表单提交之前和之后。

      您应该使用自定义验证器(就像您在初始代码中所做的那样)。 但由于检查是否使用了用户名或电子邮件可能会触发 HTTP 调用,因此您必须使用 异步验证器

      在表单声明中,异步验证器出现在同步验证器之后:

      this.userForm = fb.group({
        // `userExists` is in 3rd position, it's an async validator
        username: ['', Validators.required, userExists],
        password: []
      });
      

      现在是userExists 的代码。由于它是一个异步验证器,它必须返回一个可观察的或一个承诺:

      // This is just a standard function
      // but you could also put that code in a class method.
      function userExists(control: AbstractControl): Observable<{[key: string]: any}> {
        // The userName to test.
        const userName = control.value;
      
        // NB. In a real project, replace this observable with an HTTP request
        const existingUsernames = ['kevin', 'vince', 'bernard'];
        return Observable.create(observer => {
          // If the username is taken, emit an error
          if (existingUsernames.indexOf(userName) !== -1) {
            observer.next({usernameTaken: true});
          }
          // Username is available, emit null
          else {
            observer.next(null);
          }
          // The observable MUST complete.
          observer.complete();
        });
      }
      

      使用此 Plunkr 中的代码:https://plnkr.co/edit/aPtrp9trtmwUJDJHor6G?p=preview — 尝试输入现有用户名('kevin'、'vince' 或 'bernard'),在提交表单之前,您会看到一条错误消息。

      为什么您的代码不起作用?我看到几个错误:

      • 您使用了同步验证器而不是异步验证器。
      • 您的验证器函数是一个工厂函数(= 返回另一个函数的函数)。仅当您需要使用特定参数自定义验证器时才需要它。这不是你的情况,所以你应该只使用常规函数(即在alreadyExist() 中,只保留return 之后的代码)。
      • 另外,提交表单后设置错误的逻辑并不理想。

      【讨论】:

      • 你好 AngularFrance,谢谢你的回复! =)。我完全同意你的观点,我已经看过很多次异步验证器,但在我的情况下,我没有一个(API)可以为我控制电子邮件的有效性。相反,我有一个 Web 服务,它存储一个新用户并为我提供 OK 或 KO(KO 取决于错误,但如果错误状态为 401,则电子邮件已经存在)。我将来会实现异步验证器。同时,我只是在订阅“catch”中附加了一个错误。
      • 我认为,对于登录表单,问题是一样的。在现实世界中,我们不能使用异步验证器来检查组合用户/密码是否良好。如果组合为假,我们必须等待响应并显示错误。
      • 所以你是说你没有办法在不尝试创建帐户的情况下检查电子邮件是否已被占用?
      • 是的。一个可操作的网络服务......我可以创建一个假服务并将其用作 ngModule 的提供者声明中的别名。
      • 是的,但是你说服了我,我做了一个假服务,无论如何,如果我之前过滤,已经存在的 web 服务不应该返回 401 错误。谢谢!
      猜你喜欢
      • 2017-03-02
      • 2013-07-23
      • 2019-08-25
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 2019-03-12
      • 1970-01-01
      • 2019-04-26
      相关资源
      最近更新 更多