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?
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 .
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.
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.
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>
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 {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With