仅当第一个输入字段不为空时才在第二个输入字段中添加验证器

问题描述 投票:0回答:2

我正在使用 Angular Forms 开发一个表单,但我遇到了一个死胡同,我想仅当第一个输入字段不为空时才向第二个输入字段添加验证。

假设我有两个输入字段:姓名和年龄。因此,当在姓名中输入某些内容时,只有年龄才会被设置为必填。我在表单中使用 FormGroup 和 FormControl,这就是组件文件现在的样子,没有年龄验证器:

class Component implements OnChanges {
  @Input() name: string;
  @Input() age: string; 

  form = new FormGroup({
    name: new FormControl(''),
    age: new FormControl('')
  });

  ngOnChanges(changes) {

    if (changes.name?.currentValue !== changes.name?.previousValue) {
      this.setName(changes.name.currentValue);
    }

    if (changes.age?.currentValue !== changes.age?.previousValue) {
      this.setAge(changes.age.currentValue);
    }
  }

  setName(name) {

    this.form.patchValue({
      name,
    });

    if (name) {
      this.form.get('age').setValidators([
         Validators.required,
         this.form.get('age').validator
      ]);
    } 
    
  }

  setAge(age) {
    this.form.patchValue({
      age,
    });
  }

}

这是模板:

<custom-input
      label="Name"
      placeholder="name"
      name="name"
      formControlName="name"
></custom-input>

<custom-input
      label="Age"
      placeholder="age"
      name="age"
      formControlName="age"
></custom-input>
angular validation angular-reactive-forms
2个回答
5
投票

您可以使用以下方法!

监听您想要的表单字段的更改事件,然后检查该字段是否已填充,然后我们可以使用命令

setValidators
切换所需的内容,然后在更新后我们可以通过运行
updateValueAndValidity
确保表单同步这将重新验证表格!

ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import {
  FormBuilder,
  FormControl,
  FormGroup,
  Validators,
} from '@angular/forms';
import { Subscription } from 'rxjs';
import { pairwise, startWith } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit, OnDestroy {
  name = 'Angular';

  form: FormGroup;
  subscription: Subscription;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.form = this.formBuilder.group({
      control1: [''],
      control2: [''],
    });
  }
  control1Change() {
    const control1 = <FormControl>this.form.get('control1');
    const control2 = <FormControl>this.form.get('control2');
    if (control1.value) {
      control2.setValidators([Validators.required]);
    } else {
      control2.setValidators(null);
    }

    control2.updateValueAndValidity();
  }
  control2Change() {
    const control1 = <FormControl>this.form.get('control1');
    const control2 = <FormControl>this.form.get('control2');
    if (control2.value) {
      control1.setValidators([Validators.required]);
    } else {
      control1.setValidators(null);
    }

    control1.updateValueAndValidity();
  }

  ngOnDestroy(): void {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}

HTML

<hello name="{{ name }}"></hello>
<form [formGroup]="form">
  <div style="margin-bottom: 1rem">
    <label for="control1">Make Field 2 required</label>
    <input
      id="control1"
      type="text"
      formControlName="control1"
      (change)="control1Change()"
    />
    <span
      *ngIf="form.controls.control1.hasError('required')"
      style="color: red; display: block; margin-top: 0.25rem;"
      >Field 2 is required</span
    >
  </div>
  <div style="margin-bottom: 1rem">
    <label for="control2"> Field 2 </label>
    <input
      id="control2"
      type="text"
      formControlName="control2"
      (change)="control2Change()"
    />
    <span
      *ngIf="form.controls.control2.hasError('required')"
      style="color: red; display: block; margin-top: 0.25rem;"
      >Field 2 is required</span
    >
  </div>
  <div>
    <button type="submit" [disabled]="!form.valid">
      Only enabled when form is valid
    </button>
  </div>
</form>

分叉堆栈闪电战


0
投票

我有同样的需求,这是我基于自定义验证器的解决方案。

在这种情况下,如果

formControlA
的值不为空,则需要
formControlB

这是我的自定义验证器:

/**
 * Generates a validator function that checks if a reference control is not null.
 *
 * @param {string} referenceControlName - The name of the control in the same form group that holds the reference value.
 * @return {ValidatorFn} A validator function
 */
export function RequiredIfControlIsNotNullValidator(referenceControlName: string): ValidatorFn {
  return (currentControl: AbstractControl): { [key: string]: any } => {
    // Get the reference control from the parent formGroup
    const referenceControl = currentControl.parent ? currentControl.parent.get(referenceControlName) : null;
    
    // Throw an error if the reference control is null or undefined
    if (referenceControl == null)
      throw Error("Reference formControl is null or undefined");
    
    // Check if the reference control value is null or undefined
    const refValueIsNullOrUndefined = referenceControl.value == null || referenceControl.value == undefined;
    
    // Return the validation result
    return refValueIsNullOrUndefined ?  null : { [`${referenceControlName}IsNotNull`]: true };
  };
}

在您的组件中,以这种方式将其分配给您的 formControl :

this.myForm = new FormGroup({
  formControlA: new FormControl<string | null>({ value: null, disabled: false }, [Validators.nullValidator]),
  formControlB: new FormControl<string | null>({ value: null, disabled: false }, [RequiredIfControlIsNotNullValidator('formControlA')])
});

但是,每次

formControlB
的值更新时,我们都需要运行
formControlA
的验证。因此,在组件的 ngOnInit 中,对
formControlA

的 valueChanges 做出反应
public ngOnInit(): void {
// [...]
  this.myForm.get("formControlA").valueChanges.subscribe(vc => {
    this.visitForm.get('formControlB').updateValueAndValidity();
  });
// [...]
}

然后,验证器会生成一个自定义错误密钥,因此您可以使用它在模板中显示适当的错误消息

<form [formGroup]="myForm">
  <div>
    <input formControlName="formControlA" />
  </div>
  <div>
    <input formControlName="formControlB" />
    <span class="error" *ngIf="myForm.get('formControlB').hasError('formControlAIsNotNull')">
      The value of A is not null, hence B is required
    </span>
  </div>
</form>
© www.soinside.com 2019 - 2024. All rights reserved.