如何直接从formControl获取Validators?

9

输入图像描述

输入图像描述

输入图像描述

我有一个电子邮件字段,并添加了两个验证器(必需,电子邮件),我想在 输入事件 上检查验证状态,以在其有效时调用系统成员的 API 并检查,如果无效则不要调用 API 并且不要在页面上显示错误消息。

当焦点离开电子邮件字段时,我将在模糊事件(focusOut email's input)上显示错误消息,首先我使用formControl.validator(formControl)来触发验证器并检查formControl.valid,我成功地得到了有效状态,但它会在页面上显示错误消息,因为我已经订阅了statusChange来在状态等于invalid时显示错误消息。

目前,我将验证器保存在变量中,并传递给initEmailChaingeEvent()以在不使用statusChange事件的情况下检查验证状态。 这样可以工作,但我认为这不是一个好方法。下面是我的实现示例:

实时范例

export class AppComponent {
  public sampleForm: FormGroup;

  @ViewChild('emailElm')
  emailElm: ElementRef;

  ngOnInit() {
    this.initForm();
  }

  initForm() {
    const emailValidtors = [
      Validators.required,
      Validators.email
    ]

    const emailFC = new FormControl(null, {
      validators: emailValidtors,
      updateOn: 'blur'
    });
    //
    this.sampleForm = new FormGroup({
      'email': emailFC
    });
    //
    this.initEmailChaingeEvent({
      emailFC: emailFC,
      validtors: emailValidtors
    });
    //
    this.sampleForm.valueChanges.subscribe((val) => {
      console.log('_blue event:valueChanges', val)
    });
    //
    this.initShowErrorMsgEvent({
      fc: emailFC
    });
  }

  private initEmailChaingeEvent(arg: {
    emailFC: FormControl,
    validtors: any[]
  }) {
    fromEvent(this.emailElm.nativeElement, 'input')
      .pipe(debounceTime(500))
      .subscribe((event: Event) => {
        const currentEmail = (event.target as HTMLInputElement).value;
        // check is valid
        // **quention** : how can I get validtors from fromcontrol self 
        // if I use  arg.emailFC.validator(arg.emailFC) to ehcek status , it will trigger oberservable in initShowErrorMsgEvent(),
        //  but I just want to got valid result , I don't want to show error msg on UI at this time

        for (const validator of arg.validtors) {
          const inValid = validator(arg.emailFC);
          if (inValid) {
            console.log('input event:invalid', currentEmail);
            return;
          }
        }
        // **do sometheng when all valid**
        console.log('input event:call API , email:',currentEmail );
      });
  }

  private initShowErrorMsgEvent(arg: {
    fc: FormControl,
  }) {
    arg.fc.statusChanges
      .subscribe((status) => {
        // console.log('status' , status);
        if (status === 'INVALID') {
          // show error msg....
          console.log('_show error msg by antoher component');
        }
      });
  }
}
<form [formGroup]="sampleForm">
  <input formControlName="email" #emailElm >
</form>


1
我更新了我的问题,我在输入事件上检查输入值,并在模糊事件上显示错误消息,因为我在FormControl上设置了 updateOn:blur'.valid.invalid 将不会在输入事件上触发。 - Chunbin Li
总之,您希望在表单有效时自动将表单发送到API? - Andrew Howard
当电子邮件字段有效时,我想将其发送到API以检查是否为我的系统的成员。 - Chunbin Li
那么问题是如何进行电子邮件验证?还是在表单有效后只需发送它? - Andrew Howard
当用户输入他们的电子邮件时,通过我的FormControl验证检查,调用API以检查成员是否有效。 - Chunbin Li
3个回答

2

你把任务复杂化了。 首先,声明您的表单和控件验证器。如果您从验证器列表中组成验证器,则它们将按照定义的顺序进行检查。因此,首先是必需的,然后是“如果它是有效的电子邮件”,最后您自定义的验证器将检查它是否唯一。

 ....
 this.emailForm = this.fb.group({
       emailAddress: [null, Validators.compose([Validators.required, Validators.email, uniqueEmailValidator()])]
 });
 ...

然后,您可以通过API创建自定义验证器来检查用户电子邮件。有关自定义验证器的更多信息,请参见:Angular文档

function uniqueEmailValidator(){
    ...
}

这个解决方案是否可以防止触发 StatusChange 以显示验证错误消息? - Chunbin Li
验证器按定义顺序进行检查,如果当前的验证器失败,则不会检查下一个验证器。第一次,在“失焦”时检查验证器,如果发生错误,则在每个键按下事件上进行检查。 - Zsolt Tolvaly
我为这个解决方案创建了一个实时示例,但是你说它不起作用:验证器按定义顺序检查。 我尝试在Angular源代码中找到按顺序检查的内容,但我仍然一无所获,我的示例代码有问题吗? - Chunbin Li
1
我会在本周晚些时候发布一个可工作的示例。最近我头脑中有很多事情,抱歉! - Zsolt Tolvaly

0

这里有很多需要改进的地方。首先,我建议订阅控件的formValue变化,而不是在原生元素上使用Observable。

this.sampleForm.get('email').valueChanges.subscribe((event) => {
    // CODE IN HERE
}

ValueChanges 是 formControl 上的一个属性,当值发生变化时会触发事件。https://angular.io/api/forms/AbstractControl

接下来,要访问验证器,你只需检查表单控件是否有效。

this.sampleForm.get('email').valid();

如果任何验证器无效,它将为false,如果所有验证器都有效,则为true。
编辑:
从您的评论中听起来,似乎您想在其中添加一个debounceTime管道:
this.sampleForm.get('email').valueChanges
.pipe(debounceTime(500), distinctUntilChanged())
.subscribe((event) => {
    if (this.sampleForm.get('email').valid) {
         // Your API logic here
    }
}

DebounceTime基本上会延迟事件的处理,并且会丢弃队列中的任何待处理事件。

debounceTime会延迟源Observable发出的值,但如果源Observable有新值到达,则会丢弃之前挂起的延迟发射。http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-debounceTime


@ChunbinLi:我不太确定你的意思,如果我说错了话在这里向你道歉。你不需要显示错误消息,也不必在控件有效之前采取任何行动。从你的评论中听起来,你需要一个防抖时间管道,我已经更新了我的答案并加入了这个逻辑。 - hugmungus
我在这里添加了一张图片来描述它,邮箱字段上有两个事件(blur、input),debounceTime无法验证并且在initEmailChaingeEvent()函数中不显示消息。 - Chunbin Li
@ChunbinLi,你为什么在这里使用onBlur,有特别的原因吗? - hugmungus
@ChunbinLi 我理解你想要解决的问题,只是不太明白你的方法。使用onBlur而不是formChanges有什么原因吗? - hugmungus
如何使用formChanges而不是OnBlur? - Chunbin Li
显示剩余4条评论

0

感谢大家提供更多的想法,我通过formControl的验证器属性进行了修复,这是我的修改列表:

  • 只将值传递给验证器,避免触发statusChange发射器

实时示例

private initEmailChaingeEvent(arg:{
   emailFC : FormControl,
   ....
}) {
  ...
  const inValid = arg.emailFC.validator({
      value: currentEmail
    }
    as any);
  ....
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接