在Angular 2中

时间:2017-01-26 19:20:12

标签: angular typescript formbuilder customvalidator

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

我使用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
});

自定义hasExist()验证程序:

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

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

2 个答案:

答案 0 :(得分:5)

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

在我的情况下,对于电子邮件 FormControl ,我不需要自定义验证器(即使可以使用setValidators())。

我可以删除 alreadyExist(),并从验证器列表中删除其声明。

然后,我使用 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 有一个新错误,因此,通过这种方式,我可以为此错误附加错误消息。

答案 1 :(得分:1)

YoKévin。 :)如果我关注,您当前的工作流程是:

  1. 让用户提交表单(创建新帐户)。
  2. 如果创建新帐户失败,请手动将错误附加到表单。
  3. 不好。现在,您可以在两个地方进行验证:提交表格之前和之后。

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

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

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

    现在是userExists的代码。由于它是异步验证器,因此必须返回一个observable或promise:

    // 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之后的代码。)
    • 此外,提交表单后设置错误的逻辑并不理想。