Angular 4 : Form invalid despite no errors in fields (using custom validation)

标签 angular custom-validators

我正在尝试使用自定义验证来验证表单。出于某种原因,我必须构建一个可以更改电子邮件或设置新密码的表单。出于这个原因,我不能使用 Validators.required,因为密码字段只有在被触摸时才会变成必需的。

我的问题是,当输入验证解决后,表单仍然无效。

我做了一个 plnkr 来演示我的问题:
http://plnkr.co/edit/obF4gC5RHkXOOlCEsIuH?p=preview

ngOnInit(): void {
    this.emailField = new FormControl('mail@mail.com', Validators.email);
    this.pw1 = new FormControl('', [this.passwordAreEqualValidator, Validators.minLength(2)]);
    this.pw2 = new FormControl('', this.passwordAreEqualValidator);
    this.pwOld = new FormControl('', this.notEmptyIfNewIsTouchedValidator);

    this.form = this.formBuilder.group({
      pw1: this.pw1,
      pw2: this.pw2,
      emailField: this.emailField,
      pwOld: this.pwOld
    });
  }

notEmptyIfNewIsTouchedValidator(control: FormControl) : ValidationErrors | null {
    if (control.dirty) {
      if (control.value === '') {
        return {
          oldPasswordEmpty: true
        }
      }

      const parent = control.parent,
            pw1 = parent.get('pw1'),
            pw2 = parent.get('pw2');

      // this will trigger nothing in template, this part is only
      // to mark form invalid if password was entered. passwordNew1
      // cannot be false by default as this is okay when you only
      // want to change your e-mail adress.
      if (pw1.value.length === 0) {
        pw1.setErrors({noPassword: true});
      } else {
        if (pw1.hasError('noPassword')) {
          let pw1Errors = pw1.errors;
          delete pw1Errors.noPassword;  
          pw1.setErrors(pw1Errors);
        }
      }

      console.log('pw1 errors: ', pw1.errors);
      console.log('pw2 errors: ', pw2.errors);
      console.log('old errors: ', control.errors);
    }

    return null;
  }

  passwordAreEqualValidator(control: FormControl): ValidationErrors | null {
    if (control.dirty) {
      const
        parent = control.parent,
        pwOld = parent.get('pwOld'),
        pw1 = parent.get('pw1'),
        pw2 = parent.get('pw2');

      if (pwOld.value === '') {
        pwOld.setErrors({oldPasswordEmpty: true})
      }

      if (pw1.value !== pw2.value) {
        return {
          notEqual: true
        };
      } else {
        let pw1Errors = pw1.errors;

        if (pw1.hasError('notEqual')) {
          delete pw1Errors.notEqual;
          pw1.setErrors(pw1Errors);
        }

        if (pw1.hasError('noPassword')) {
          delete pw1Errors.noPassword;
          pw1.setErrors(pw1Errors);
        }

        pw2.setErrors(null);

        console.log('pw1 errors: ', pw1.errors);
        console.log('pw2 errors: ', pw2.errors);
        console.log('old errors: ', pwOld.errors);
      }
    }

    return null;
  }

重现步骤:

  1. 输入密码(出现错误旧密码为空)
  2. 重复密码(错误密码不相等,直到两个密码匹配为止)
  3. 一旦您的重复密码匹配,为旧密码添加一个值(错误的旧密码被删除)
  4. 所有验证错误都已删除,但表单仍然无效。

为什么我的表单无效?

P.S:一旦我再次编辑我的 pw1,我的表单就有效了,尽管错误的结果没有改变。

最佳答案

您在两个字段上都设置了验证器.....发生的情况是当您输入 pw2 时 pw1 不会重新生效,因此 pw1 仍然无效,直到您返回并再次输入它。

在您的组件中,在 ngOnInit 的末尾,您可以添加以下内容....

    this.pw1.valueChanges().subscribe(() => this.pw2.updateValueAndValidity());
    this.pw2.valueChanges().subscribe(() => this.pw1.updateValueAndValidity());

关于 Angular 4 : Form invalid despite no errors in fields (using custom validation),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47672909/

相关文章:

Angular6:自定义组件上的输入绑定(bind)未正确更新

html - Mat Select 多个设置选定值

Angular : how to debounce an Observable?

angular - 如何静音 "The feature name "路由器“状态中不存在...”ngrx/router-store 警告

Spring 验证 : getting "Invalid target for Validator" when using two validators

javascript - Ionic 为什么 nativeElement 是 undefined 的?

Angular Forms 响应式(Reactive) - 交叉控制验证

grails - 使用对象列表进行Grails自定义验证

javascript - ASP.NET - 带有动态错误消息的自定义验证器

asp.net - 如何将 javascript 连接到 .Net 中的 CustomValidator 控件