Angular FormControl 如何检查是否为必填项

21

有没有办法检查是否需要控制?

当我实现一个专门的表单字段组件来接受FormControl时,问题就出现了。该组件不仅具有input,还具有验证错误。由于某些字段是必填的,因此让用户知道是否需要通过*表示是很好的。

有没有办法检查@Input() control: FormControl是否需要Validators.required,并显示星号?

6个回答

30

你可以像这样做:

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, AbstractControl } from '@angular/forms';

@Component({...})
export class AppComponent  {
  form: FormGroup = new FormGroup({
    control: new FormControl(null, Validators.required)
  });

  get validator() {
    const validator = this.form.get('control').validator({} as AbstractControl);
    console.log(validator);
    if (validator && validator.required) {
      return true;
    }
  }
}

然后在您的模板中:

<form [formGroup]="form" (submit)="onSubmit()">
  Control: <span *ngIf="validator">*</span> <input type="text" formControlName="control">
  <button>Submit</button>
</form>

注意: 只需使用 this.form.get('control').validator({} as AbstractControl); 获取表单控件作为AbstractControl类型即可。

这将返回一个对象,其中包含在您的FormControl上存在的验证器列表。然后,您可以检查对象中的required键是否存在以及其值是否为true,则可以确定FormControl上应用了必填项验证器。


这里是一个适用于您参考的Working Sample StackBlitz


1
非常感谢您的帮助。但是,由于某些字段没有验证器,我需要修改您的代码为const validator = this.control.validator ? this.control.validator({} as AbstractControl) : ''; - Sergey
关于具有值的验证器 minLength 等怎么样?我尝试了控制台,但只得到了 {required: true}。我正在调查 console.log(validator) - Sergey
这不是那种开箱即用的东西。阅读**此线程** 以获取更多信息。 - SiddAjmera
我想补充一点,如果您在验证器中有自定义验证函数,可能会出现错误,因为您传递的对象严格来说不是控件。您可以通过首先检查传递的对象是否具有setErrors函数来解决此问题。if (control.setErrors === undefined) return; - StefanJanssen

21

我需要一些更抽象的东西,所以我稍微改编了@siddajmera的答案,以便能够在任何字段上使用。

在你的 .ts 文件中:

isRequiredField(field: string) {
    const form_field = this.testForm.get(field);
    if (!form_field.validator) {
        return false;
    }

    const validator = form_field.validator({} as AbstractControl);
    return (validator && validator.required);
}

接着,在您的模板文件中:

<div>
    <label>Some Field:<span *ngIf="isRequiredField('some_field')">*</span></label>
    <input [formControl]="form.controls['some_field']">
</div>
<div>
    <label>Some Field:<span *ngIf="isRequiredField('another_field')">*</span></label>
    <input [formControl]="form.controls['another_field']">
</div>

2
这个答案比批准的答案好一点,因为它通过将默认值设置为getter方法来减少ERROR TypeError: form_field.validator is not a function的可能性。 - mpro
感谢您的回答。您能写一下如何处理 Object is possibly 'null' 错误在 form_field.validator({} as AbstractControl) 中吗? - johannesMatevosyan

4
根据this Angular文档,您可以使用hasValidator方法来检查控件中是否使用了内置验证器。
let abstractControl = this.formGroup.controls[this.formControlName];
const isRequired = abstractControl.hasValidator(Validators.required);

请在您的答案中提供一些解释,以使其更易理解。 - Philipp Kief

4
我有点晚了,但我认为这可以通过使用管道来解决。上面的答案解决了你的问题,但有一个小问题。直接在模板中使用方法/获取器,在每次变更检测运行时都会执行该函数,如此文章所述。在您的简短示例中可能不是性能问题,但在更大的表单中可能会成为问题。 我的解决方案 通过使用纯管道,当输入到管道的值发生更改时,对所提供的控件的检查将被触发。我已经将ControlRequiredPipe添加到了AppModuleprovidersdeclarations部分。当将管道添加到providers部分时,它也可以在Component TypeScript类中使用。我已经将这种行为包含在AppComponentOnSubmit函数中。 Stackblitz示例 AppComponent:
<form [formGroup]="form" (submit)="onSubmit()">
  Control: <strong *ngIf="form.get('control') | controlRequired">*</strong>
  <input type="text" formControlName="control">
  <button>Submit</button>
</form>

import { Component } from "@angular/core";
import { FormGroup, FormControl, Validators } from "@angular/forms";
import { ControlRequiredPipe } from "./control-required.pipe";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  form: FormGroup = new FormGroup({
    control: new FormControl(null, [
      Validators.required,
      Validators.minLength(8)
    ])
  });

  constructor(private controlRequiredPipe: ControlRequiredPipe) {}

  onSubmit() {
    alert(
      `The required state of the FormControl is: ${this.controlRequiredPipe.transform(
        this.form.get("control")
      )}`
    );
  }
}

ControlRequiredPipe:

import { Pipe, PipeTransform } from "@angular/core";
import { AbstractControl } from "@angular/forms";

@Pipe({
  name: "controlRequired"
})
export class ControlRequiredPipe implements PipeTransform {
  public transform(control: AbstractControl): boolean {
    //  Return when no control or a control without a validator is provided
    if (!control || !control.validator) {
      return false;
    }

    //  Return the required state of the validator
    const validator = control.validator({} as AbstractControl);
    return validator && validator.required;
  }
}

AppModule:

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";

import { AppComponent } from "./app.component";
import { ControlRequiredPipe } from "./control-required.pipe";

@NgModule({
  imports: [BrowserModule, FormsModule, ReactiveFormsModule],
  declarations: [AppComponent, ControlRequiredPipe],
  providers: [ControlRequiredPipe],
  bootstrap: [AppComponent]
})
export class AppModule {}

1
这个解决方案是我迄今为止读过的最好的。我的一个表单非常大(像100个字段),纯管道解决方案极大地缓解了性能问题。 - Wis
请查看我的答案,其中修复了更新的验证器问题。 - austinthedeveloper

3
我在@Hkidd的答案基础上进行了修改。只要表单验证器没有更改,此用户的答案就是正确的。以下是一个无法使用该方法的情况。
  • 5个表单值,全部不需要
  • 选中一个值的框会使用setValidators/updateValueAndValidity模式将2个控件标记为必填项
  • 这2个控件将正确地具有验证器,但星号不会显示

问题在于构建的管道不会触发第二次,因为管道仅将整个FormControl视为参数。幸运的是,这是一个简单的修复方法:

// HTML
Control: <strong *ngIf="form.get('control').validator | controlRequired">*</strong>

// PIPE
export class ControlRequiredPipe implements PipeTransform {
  public transform(validatorFn: ValidatorFn): boolean {
    //  Return when no control or a control without a validator is provided
    if (!validatorFn) {
      return false;
    }

    //  Return the required state of the validator
    const validator = validatorFn({} as AbstractControl) || {};
    return validator && validator.required;
  }
}


-7

您可以使用 required 属性。

<input type="text" formControlName="control" placeholder="Some Field" required>

此外,它对于CSS样式或可访问性目的非常有帮助。

Deivid,欢迎来到StackOverflow。很抱歉你的旅程以一个负分开始,但是你真的没有读懂问题,对吧?这不是关于使一个字段变为必填项,而是检查它是否已经是必填项。 - Robin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接