Angular2:如何确定FormControl是否具有必填验证器?

63

有没有办法查找Angular2 FormControl中是否为控件注册了必需的验证器。

this.form = builder.group({name: ['', Validators.required]};

如果我想查询this.form.controls['name']控件是否为必填字段,那么该怎么办呢?我知道我可以检查它是否有效,但这不是我想要的。

此致敬礼, 马克


你找到解决问题的方法了吗? - Franziskus Karsunke
@marc,你找到解决方案了吗?我最接近的方法是使用AbstractControl或FormControl的“getError()”方法,但它在生命周期中填充得太晚了。 - Spikeh
我也需要针对这种情况的解决方案。(知道表单字段是否必填,而不进行验证,只需知道是否必填,有值或无值),你找到解决方案了吗? - Ninja Coding
10个回答

75

这个函数应该适用于FormGroup和FormControl。

  export const hasRequiredField = (abstractControl: AbstractControl): boolean => {
    if (abstractControl.validator) {
        const validator = abstractControl.validator({}as AbstractControl);
        if (validator && validator.required) {
            return true;
        }
    }
    if (abstractControl['controls']) {
        for (const controlName in abstractControl['controls']) {
            if (abstractControl['controls'][controlName]) {
                if (hasRequiredField(abstractControl['controls'][controlName])) {
                    return true;
                }
            }
        }
    }
    return false;
};

5
这应该是被接受的答案。它完美地起作用了,非常感谢! - rmcsharry
直到今天我再次看到第三行才明白。因此,验证器函数是公开的,并且可以在任何控件上调用;您正在对一个伪装成控件的空对象进行调用。明白了。我的问题是:为什么这只适用于必需验证器?我尝试在仅具有minLength验证器的字段上尝试了这个技巧,但生成的对象为空。除了必需之外,这个技巧还可以用来检查其他内容吗? - pbristow
1
@MarcelTinner - 这里是如何实现您的解决方案并获得良好性能的要点:https://gist.github.com/jsdevtom/5589af349a395b37e699b67417ef025b - Tom
1
abstractControl.validator 不是 AbstractControl 类型的函数,它该如何工作? - Vinutha Kumar
为什么你返回 false 而不是 null - Andre Elrico
显示剩余2条评论

24
Angular现在提供了hasValidator,您可以使用它来检查一个formcontrol是否具有同步验证器。如果您需要检查它是否具有异步验证器,也可以使用hasAsyncValidator
在您的情况下,当您想要检查formcontrol是否为必填项时,您可以这样做:
this.form.get('name').hasValidator(Validators.required);

编辑:TypeScript现在通常会抱怨
“类型'AbstractControl'上不存在属性'hasValidator'”
你需要告诉TypeScript这实际上是一个FormControl(而不仅仅是基类AbstractControl)。所以例如以下代码应该可以正常工作:
(this.form.get('name') as FormControl).hasValidator(Validators.required);

这会产生一个错误:“类型'AbstractControl'上不存在属性'hasValidator'。” 这种方法可能已被弃用。 - Tomas Katz
@TomasKatz 嗯...答案已经链接了官方文档,并且显示应该是有效的。你使用的Angular版本是什么?hasValidator()是在12版中引入的,因此在此之后的任何版本中,这个答案都应该是有效的。 - AT82
hasValidator() 只在 Angular 12 中存在。 - chitgoks
@chitgoks 这是不正确的,我的回答中有一个链接指向文档,至今仍然存在。"hasValidator"确实存在 :) - AT82
@AT82 我忘记了我的版本是什么(我想是10),但它并不存在。真的。 - chitgoks

16

虽然没有 Angular API 直接查找特定字段是否设置了 required 验证器,但可通过以下方式间接实现:

import { NgForm, FormControl } from '@angular/forms';

const isRequiredControl = (formGroup: NgForm, controlName: string): boolean => {
    const { controls } = formGroup
    const control = controls[controlName]
    const { validator } = control
    if (validator) {
        const validation = validator(new FormControl())
        return validation !== null && validation.required === true
    }
    return false
}

我已经进行过测试,只有在特定的FormControl中添加了Validator.Required验证器时,它才会触发。


5

目前没有方法可以检查验证器或获取所有验证器:https://github.com/angular/angular/issues/13461

@fairlie-agile的解决方案非常聪明。但我认为我们必须使用空的FormControl,因为我们需要触发必填验证器,this.group.controls[this.config.name] 可能已经用某个值初始化。

ngOnInit() {
    let formControl = this.group.controls[this.config.name];
    let errors: any = formControl.validator && formControl.validator(new FormControl());
    this._required = errors !== null && errors.required;
}

2

一种方法是在表单加载时检查控件是否有效,以查看它是否具有所需的错误(如果字段为空,则会出现此错误)。

这对于其他验证器(例如minLength)不起作用,因为它们直到更改控件才会触发。

export class FormInputComponent implements Field, OnInit {
  private _required: boolean;
  config: FieldConfig;
  group: FormGroup;

    /** Readonly properties. */
  get required(): boolean { 
    return this._required;
  }

  ngOnInit() {
    var _validator: any = this.group.controls[this.config.name].validator && this.group.controls[this.config.name].validator(this.group.controls[this.config.name]);
    this._required = _validator && _validator.required;
  }
}

不是一个很好的解决方案,因为输入可能在初始化时被填充了一个值。 - dave0688

2

我有类似的问题。目前,我正在使用这个:

  import { Attribute } from '@angular/core';

  // "Kind-of" hack to allow "pass-through" of the required attribute
  constructor(@Attribute('required') public required) {
    // call super here if the component is an ancestor
  }

我很困惑为什么FormControl中包含了像“disabled”这样的属性,但没有“required”。


1
因为在表单API中,require关键字并没有特殊的含义,它只是可能出现的错误之一。如果您要创建一个特殊的验证器来填充“error”属性“notABanana”,您肯定不希望它出现在AC上,对吧?但我认为我们需要一种方法来访问给定AC上的当前验证器。 - realappie

1
我用以下代码解决了类似的问题:

get lastPriceField(): AbstractControl {
    return this.form.get('last_price');
}

private checkIfFieldHasValidatorRequired() {    
    const validators = (this.lastPriceField as any)._rawValidators;
    this._lastPriceIsRequired = validators && validators.some(item => item.name === "required");
}

0

假设最初仅注册的错误是required错误

// in your component you'll have access to `this.myFormGroup`
const formGroup = {
  controls: {
    email: {
      errors: {
        required: true
      }
    },
    username: {
      errors: null
    }    
  }
}

// required by default
let required = {
  email: '*',
  username: '*',
};

// in `ngOnInit`
required = Object.entries(formGroup.controls)
  .map(([key, control]) => [key, control.errors])
  .filter(([, errors]) => !errors)
  .map(([key]) => [key, ''])
  .reduce((_required, [key, isRequired]) => Object.assign(_required, { [key]: isRequired }), required)

// in your template you may write `<label>Email{{ required.email }}</label>`
console.log(required)


0
一个简短的版本。 首先,创建一个空控件以避免在方法中不断地执行它。
  private readonly emptyFormControl = new FormControl();

然后在方法中进行检查。如果控件已启用并且其验证器在验证空控件时出现“必填”错误,则必须使用控件。

  private isMandatory = (fc: FormControl): boolean =>
    fc.enabled && !!fc.validator && !!fc.validator(this.emptyFormControl)?.required;

这仅适用于FormControl对象。如果您需要支持FormGroup或/和FormArray,则需要将递归添加到检查方法中。


-4

我不知道检查控件是否有必填验证器的确切方法是什么。

但是可以采用以下解决方法,每当控件具有必填验证器时,它会向该控件添加validator()函数。

例如:

<input type="text" formControlName="firstname">

constructor(private formBuilder: FormBuilder){
    this.registerForm = this.formBuilder.group({
        firstname: ['', Validators.required]     //<<<===one required validation on firstname control
    });

    console.log(this.registerForm.controls.firstname.validator.length);
                                                 //<<<===this will return 1.
   });

}

在上面的代码中,验证器的长度为1。
  console.log(this.registerForm.controls.firstname.validator.length);
                                                 //this will return exception

这行代码将返回1。如果没有附加验证器,那么firstname将不会有validator()函数,因此在这种情况下,我会抛出异常。

演示:https://plnkr.co/edit/I7b5JNAavmCJ6Py1eQRr?p=preview


3
这只会告诉你是否存在验证器,而不是特定所需的验证器,这正是 OP 所问的。 - GFoley83

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