具有动态值的最大值验证器

Maximum value validator with dynamic value

我有一项服务,其中 returns 用户拥有的代表金钱的价值,我希望用户能够以等于或小于总金额的价值进行交易。我试过像这样使用最大验证:

valid() {
        const form: FormGroup = this._fb.group({
          fond: ['', [Validators.required]],
          serie: ['', [Validators.required]],
          account: ['', [Validators.required, Validators.min(1)]],
          value: ['', [Validators.required, Validators.min(1)]],
          subAccount: ['', [Validators.required, Validators.min(1)]]
        });
        return form;
      }

但是不行,好像max()中的值必须从一开始就设置,所以它会假定totalAmount为undefined。

更新您已编辑的问题:

使用这个:

value: ['', [
  Validators.required, 
  Validators.min(1), 
  (control: AbstractControl) => Validators.max(this.totalAmount)(control)
]]

您可以使用以下语法实现:

(control: AbstractControl) => Validators.max(this.totalAmount)(control)

为什么?

  • 当您提供 Validators.max(this.totalAmount) 时,它会使用给定参数(this.totalAmount 的当前值)创建一个验证函数,然后将其分配给表单控件。
  • 当您使用粗箭头功能时,分配给表单控件的是粗箭头定义本身。每次调用粗箭头函数时(在有效性检查期间),它都会重新评估 Validators.max(this.totalAmount) 并使用当前值 this.totalAmount 创建新的验证函数,从而使其成为动态的。

如果您使用反应形式,请执行以下操作:

将此添加到您的 formBuilder.group

 offerPrice: [this.offer.offerPrice, [Validators.required, Validators.pattern('^\d+(\.\d{1,2})?$'), Validators.pattern('^[1-9]+[0-9]*$'),
        (control: AbstractControl) => Validators.max(this.maxAmount)(control),
        (control: AbstractControl) => Validators.min(this.minAmount)(control)]],

在您的 html 上,使用如下:

<div class=" form-group">
              <mat-form-field>
                <input class="form-control" matInput formControlName="offerPrice" placeholder="Gift Amount" [ngClass]="{'is-invalid': submitted && f.offerPrice.errors}"  *ngIf="!useSlab"/>
                <div *ngIf="submitted && f.offerPrice.errors">
                  <mat-error *ngIf="f.offerPrice.errors.required">This is required</mat-error>
                  <mat-error *ngIf="f.offerPrice.errors.min">Minimum offer price should be {{minAmount}}</mat-error>                  
                  <mat-error *ngIf="f.offerPrice.errors.max">Maximum offer price should be {{maxAmount}}</mat-error>
                  <mat-error *ngIf="f.offerPrice.errors.pattern">Price should be greater than zero</mat-error>
                </div>
              </mat-form-field>
            </div>

只是对前面答案的一点补充,当你需要设置同一个表单的另一个formControl的一个formControl的验证器的值时,你可以在没有验证器的情况下初始化表单,然后注册它们,就像这个:

const form: FormGroup = this._fb.group({
      from: [''],
      to: ['']
});

form.controls.from.setValidators([
    Validators.required,
    (control: AbstractControl) => Validators.max(this.form.controls.to.value)(control)
]);

to也是如此。

一个强大而清晰的解决方案是使用setValidators()

当您使用 setValidators() 时,代码更容易让其他人理解,并且当您要使用的动态值可能会根据用户在表单中的输入而改变时,此解决方案也适用。

例如,在你的组件中有这样的东西:

  setInputValidation() {
    this.totalAmount = this.countryOfOrigin?.value === 'US' ? 40 : 30;
    this.value?.setValidators(Validators.max(this.totalAmount));
  }

您可以根据此动态值在模板中显示自定义错误:

 <mat-error *ngIf="value?.hasError('max')">
    Must be less than {{ totalAmount }}.
 </mat-error>

在我处理的案例中,我在表单中有一个下拉列表需要更改另一个输入的 max 验证。所以我使用了上面的代码,然后简单地将其添加到下拉列表的 mat-select 中:

<mat-select formControlName="countryOfOrigin"
    (selectionChange)="setInputValidation()"
    name="country">
  <mat-option *ngFor="let country of countries" value="country">
    {{ country }}
  </mat-option>
</mat-select>

瞧,每次用户从下拉列表中做出选择时,输入的有效最大值都会发生变化,错误将根据新值显示。

注意:如果您的输入还有其他验证器,您在使用setValidators()时必须添加它们。