Angular FormControl 值的变化会触发 formgroup 中的每一次变化

Angular FormControl value changes triggers every change in formgroup

我正在尝试进行 api 调用以检查用户电子邮件的唯一性,但问题是值更改会触发所有表单控件中的每个更改。

这是我的代码:

Errors(){
  this.form01.valueChanges
    .subscribe((changedObj: any) => {
      this.valid = this.form01.valid;
      // Checks wether the email exists or not
      if (this.form01.get("email").valueChanges) {
        console.log("value of email changed");
      }
    });

}

我的表单组:

// Form Group And It's Form Controls
  form01 = new FormGroup({
    firstName: new FormControl('', [Validators.required]),
    lastName: new FormControl('', [Validators.required]),
    email: new FormControl('', [Validators.required, Validators.email]),
    phone: new FormControl('', [Validators.required]),
    password: new FormControl('', [Validators.required]),
    roleID: new FormControl('', [Validators.required]),
  });

我的输入:

<form #addCityForm="ngForm" (ngSubmit)="create()" [formGroup]="form01">
    <div mat-dialog-content>
        <!-- First Name -->
        <p>
            <mat-form-field appearance="legacy">
                <mat-label>First Name</mat-label>
                <input matInput name="firstName" formControlName="firstName" [(ngModel)]="model.firstName" placeholder="First Name">
                <mat-error *ngIf="!valid">{{getError('firstName')}}</mat-error>
            </mat-form-field>
        </p>

        <!-- Last Name -->
        <p>
            <mat-form-field appearance="legacy">
                <mat-label>Last Name</mat-label>
                <input matInput name="lastName" formControlName="lastName" [(ngModel)]="model.lastName" placeholder="Last Name"> 
                <mat-error *ngIf="!valid">{{getError('lastName')}}</mat-error>   
            </mat-form-field>
        </p>

        <!-- Email -->
        <p>
            <mat-form-field appearance="legacy">
                <mat-label>Email</mat-label>
                <input matInput name="email" formControlName="email" [(ngModel)]="model.email" placeholder="Email">  
                <mat-error *ngIf="!valid">{{getError('email')}}</mat-error>          
                <mat-hint class="validation-error" *ngIf="emailTaken">This Email is taken</mat-hint>  
                      
            </mat-form-field>
        </p>

        <!-- Phone -->
        <p>
            <mat-form-field appearance="legacy">
                <mat-label>Phone</mat-label>
                <input matInput name="phone" formControlName="phone" [(ngModel)]="model.phone" placeholder="Phone">
                <mat-error *ngIf="!valid">{{getError('phone')}}</mat-error>
                <mat-hint class="validation-error" *ngIf="phoneTaken">This Phone is taken</mat-hint>  
            </mat-form-field>
        </p>

        <!-- Role -->
        <p>
            <mat-form-field class="example-full-width">
              <mat-label>Role</mat-label>
              <input name="roleID" type="text" placeholder="Role"
                  aria-label="Employee" matInput formControlName="roleID" [matAutocomplete]="auto">
                  <mat-autocomplete #auto="matAutocomplete">
                      <mat-option *ngFor="let role of roles" [value]="role.name" (click)="customRole(role.id)">
                          {{role.name}}
                      </mat-option>
                  </mat-autocomplete>
                 <mat-error *ngIf="!valid">{{getError('roleID')}}</mat-error>
                </mat-form-field>
          </p>

        <!-- Password -->
        <p>
            <mat-form-field appearance="legacy">
                <mat-label>Password</mat-label>
                <input type="password" matInput name="password" formControlName="password" [(ngModel)]="model.password" placeholder="Password">
                <mat-error *ngIf="!valid">{{getError('password')}}</mat-error>
            </mat-form-field>
        </p>

    </div>
    <div mat-dialog-actions>
        <button mat-dialog-close [mat-dialog-close]="model" [disabled]="!valid" mat-button type="submit">Save</button>
        <button mat-dialog-close mat-button type="button">Close</button>
    </div>
    
</form>

这里是 getError 函数

// Errors Messages
getError(field: string){
  if (this.form01.get(field).hasError('required')) {
    return "You must enter a value";
  }
  if (this.form01.get(field).hasError('email')) {
    return "Invalid Mail";
  }
}

输入 firstName 或 lastName 输入时的结果:

value of email changed

我希望仅当电子邮件输入更改时才触发值更改。 提前致谢!

您可以为此使用 get() 函数:

this.form01.get("email").valueChanges
    .subscribe(email => {
      console.log(email);
    });

另一种方法是手动检查最新值:

lastEmail: string;

Error() {
  this.form01.valueChanges
    .subscribe(obj => {
        if (lastEmail !== obj?.email) {
            lastEmail = obj?.email;
            console.log(lastEmail);
        } 
    });
}

PS:您应该考虑对每个新值调用 api 调用可能会带来问题,因为可能会发生多个 api 调用。

我建议您使用不同的最新值限制 api 调用,在最后一次更改后几秒钟。

你可以看到 .

为此您需要订阅电子邮件控件的 valueChange,而不是整个表单。

可能是这样的:

this.form01.get("email").valueChanges
  .subscribe((emailValue: string) => {
    // you have email value here
  });

但是

反应式表单有一个异步验证器选项。我认为它更适合这种情况。这样 Angular 将为您处理所有错误和表单状态。

另外一个提示,添加一个带有一些延迟的 debounceTime() 管道,这样它就不会在每次击键时发送请求。这样你就可以节省你的后端。

文档:https://angular.io/guide/form-validation#creating-asynchronous-validators