Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular FormControl check if required

Is there a way to check whether control is required?

The problem arose when I implemented a dedicated form field component which accepts FormControl and has not only input but also validation errors. Since some field are required it's good to let the user know if it's required by *.

Is there a way to check the @Input() control: FormControl for Validators.required and display an asterisk?

like image 930
Sergey Avatar asked Nov 30 '18 12:11

Sergey


People also ask

How do you check if a FormControl is required?

validator({} as AbstractControl); This will return an Object with the list of validators that are present on your FormControl . You can then check for the required key in the Object. If it exists and its value is true then you can be sure that a Required Validator is applied on the FormControl .

What is difference between FormBuilder and FormControl?

In Angular, a reactive form is a FormGroup that is made up of FormControls. The FormBuilder is the class that is used to create both FormGroups and FormControls. I encourage you to check out those links to see the full class definitions of all three.


3 Answers

You can do something like this:

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;
    }
  }
}

And then in your Template:

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

NOTE: Just get the form control as a type of AbstractControl using this this.form.get('control').validator({} as AbstractControl);

This will return an Object with the list of validators that are present on your FormControl. You can then check for the required key in the Object. If it exists and its value is true then you can be sure that a Required Validator is applied on the FormControl.


Here's a Working Sample StackBlitz for your ref.

like image 193
SiddAjmera Avatar answered Sep 25 '22 13:09

SiddAjmera


I needed something slightly more abstract, so I've adapted the answer from @siddajmera a bit to be able to use on any field.

In your .ts file:

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);
}

Then, in your template file:

<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>
like image 39
random_user_name Avatar answered Sep 26 '22 13:09

random_user_name


I'm a bit late to the game but I think this could be solved by using a Pipe. The answers above solve your problem but there is a small caveat. By directly using a method/getter in your template, this function is executed every change detection run as stated in this article. It might not be a performance issue in your short example but might be a problem in larger forms.

My solution

By using a pure Pipe the check on the provided control is fired once the input value to the Pipe has changed. I've added the ControlRequiredPipe to the AppModule providers and declarations parts. When the pipe is added to the providers part, it can be used in a Component TypeScript class as well. I've included this behavior in the OnSubmit function in the AppComponent.

Stackblitz example

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 {}
like image 28
Hkidd Avatar answered Sep 26 '22 13:09

Hkidd