简体   繁体   English

Angular 表单不会验证您是否在单击之前不离开该字段

[英]Angular form doesn't validate if you don't leave the field before clicking

I have an angular form that has validations on it.我有一个 angular 表单,上面有验证。 The form works great if you click outside the boxes before trying to submit the form.如果您在尝试提交表单之前单击框外,该表单效果很好。 Otherwise, if you hit enter, or click the submit button prior to having left all the boxes, it does nothing the first time because it doesn't see the form as valid yet.否则,如果您在离开所有框之前按回车键或单击提交按钮,它第一次什么也不做,因为它还没有看到表单有效。 On the next attempt, it submits though.但在下一次尝试时,它会提交。

I'm not sure what would cure the problem.我不确定什么可以解决这个问题。 The register method checks to see if the form is valid, but at the time the button is clicked the validation hasn't completed yet, since the onblur event has not completed on the last box data was entered in on. register方法检查表单是否有效,但在单击按钮时验证尚未完成,因为 onblur 事件在最后一个框数据输入时尚未完成。 Since the onblur event completes as a matter of clicking the button, maybe there is a way to either fake the onblur, or at least wait for it prior to the form submission?由于 onblur 事件通过单击按钮完成,也许有一种方法可以伪造 onblur,或者至少在表单提交之前等待它?

Anyway, I'm not sure if there is a need for the code with this problem, but I will add what I think to be the most pertinent of the code.无论如何,我不确定是否需要有这个问题的代码,但我会添加我认为最相关的代码。

Form html:表格 html:

    <mat-card>
      <mat-card-title>Register</mat-card-title>
      <mat-card-content>
        <form [formGroup]="form" (ngSubmit)="register(form.value)">
          <p>
            <mat-form-field>
              <input type="text" matInput placeholder="Username" formControlName="username">
              <mat-error *ngIf="checkError('username', 'required')">Username is required</mat-error>
              <mat-error *ngIf="checkError('username', 'existingUser')">Username is already taken</mat-error>
            </mat-form-field>
          </p>
          <p>
            <mat-form-field>
              <input type="password" matInput placeholder="Password" formControlName="password">
              <mat-error *ngIf="checkError('password', 'required')">Password is required</mat-error>
            </mat-form-field>
          </p>
          <p>
            <mat-form-field>
              <input type="password" matInput placeholder="Retype Password" formControlName="re_password">
              <mat-error *ngIf="checkError('re_password', 'required')">Retype Password Required</mat-error>
              <mat-error *ngIf="checkError('re_password', 'confirmedValidator')">Passwords must match</mat-error>
            </mat-form-field>
          </p>
          <p>
            <mat-form-field>
              <input type="text" matInput placeholder="First Name" formControlName="first_name">
              <mat-error *ngIf="checkError('first_name', 'required')">First name is required</mat-error>
            </mat-form-field>
          </p>
          <p>
            <mat-form-field>
              <input type="text" matInput placeholder="Last Name" formControlName="last_name">
              <mat-error *ngIf="checkError('last_name', 'required')">Last name is required</mat-error>
            </mat-form-field>
          </p>
          <p>
            <mat-form-field>
              <input type="text" matInput placeholder="Email" formControlName="email">
              <mat-error *ngIf="checkError('email', 'required')">Email is required</mat-error>
              <mat-error *ngIf="checkError('email', 'email')">Invalid email</mat-error>
              <mat-error *ngIf="checkError('email', 'existingEmail')">User with that email already exists</mat-error>
            </mat-form-field>
          </p>
          <p *ngIf="errors" class="error">
            {{errors}}
          </p>
          <div class="button">
            <button type="submit" mat-button>Register</button>
          </div>
    
        </form>
      </mat-card-content>
    </mat-card>

Formgroup:表格组:

    this.form = this.fb.group({
      username: new FormControl('', {
        validators: [Validators.required],
        asyncValidators: [this.userValidator.existingUserValidator()],
        updateOn: 'blur',
      }),
      password: new FormControl('', [
          Validators.required,
          Validators.minLength(8),
        ],
      ),
      re_password: new FormControl('',
        Validators.required,
      ),
      first_name: new FormControl('',
        Validators.required,
      ),
      last_name: new FormControl('',
        Validators.required,
      ),
      email: new FormControl('', {
        validators: [
          Validators.required,
          Validators.email,
        ],
        asyncValidators: [this.emailValidator.existingEmailValidator()],
        updateOn: 'blur',
      }),
    }, {
      validators: MatchValidator('password', 're_password'),
    });

register method: register方法:

    register(values): void {
      if (this.form.valid) {
        this.userService.register(values);
      }
    }

EDIT: To help people with similar but unrelated issues realize that their issue may be unrelated, this problem was caused by an asynchronous validation on the form field prior to submission.编辑:为了帮助有类似但不相关问题的人意识到他们的问题可能不相关,这个问题是由提交之前对表单字段的异步验证引起的。 I assumed it was simply because the last field used had a validator.我认为这仅仅是因为使用的最后一个字段有一个验证器。

You're forcing the form to use updateOn: 'blur' which means “Dont validate the input fields until the Form loses the focus”.您正在强制表单使用 updateOn: 'blur' ,这意味着“在表单失去焦点之前不要验证输入字段”。

If you are not using server side (async) validations you can use the “default” strategy of validation which is updateOn:'change' so the Validator is run each time the user press a Key.如果您不使用服务器端(异步)验证,则可以使用“默认”验证策略,即 updateOn:'change',因此每次用户按下键时都会运行验证器。

There is a third strategy which is updateOn: 'submit': Validators of each field are not run until you hit “submit”.第三种策略是 updateOn: 'submit':每个字段的验证器在您点击“提交”之前不会运行。

it validates correctly.它验证正确。 Material elements just don't show errors untill the element becomes touced(and it becomes touched after the first blur).直到元素被触摸(并且在第一次模糊后被触摸),材质元素才会显示错误。 It is considered a good practice from UX point of view, because you should be less offensive when asking user to fill your form.从 UX 的角度来看,这被认为是一种很好的做法,因为在要求用户填写表单时应该不那么冒犯。 But if you still don't like that behavior then feel free to rewrite default ErrorStateMatcher但是如果你仍然不喜欢这种行为,那么可以随意重写默认的ErrorStateMatcher

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control, form) {
    return control && control.invalid; // will show error in every case when control is invalid. i.e. field will be red from the very beginning.
  }
}

export class MyComponent {
...
customMatcher = new MyErrorStateMatcher();
}
.....
 <input matInput [errorStateMatcher]="customMatcher">

I just did this.我只是这样做了。

I wanted to show required errors on button click when user doesn't even touch the form and still presses the button (don't want to disable if invalid form)当用户甚至没有触摸表单并且仍然按下按钮时,我想在按钮单击时显示所需的错误(如果表单无效,不想禁用)

this.loginForm.markAllAsTouched();

this sets all elements as touched & in HTML *ngIf as这会将 HTML *ngIf 中的所有元素设置为已触摸和

 <span *ngIf="loginForm.get('email')?.invalid && loginForm.get('email')?.touched" >
      {{ loginForm.get('email')?.errors?.required ? 'Username Required ' : 'Invalid Username' }}
 </span>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM