How to add control in runtime and set validation in Angular?
Many times we’re in a situation on clicking on that or this, we need to open new form filed it can be anything like text, dropdown, radio button, checkbox, etc.
Let’s assume I have a select input field on select filed, we need to open other fields
In HTML
<div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="space-between">
<mat-label></mat-label>
<mat-form-field appearance="outline" fxFlex="40">
<mat-select placeholder="Select" formControlName="TreatmentAntibiotics" (selectionChange)="changeAntibotics($event)">
<mat-option *ngFor="let antb of antibotics" [value]="antb.v"> {{ antb.n }}</mat-option>
</mat-select>
</mat-form-field>
</div>
In the changeAtibiotics function, I’ll add the new Form control.
TS File
initForm(){
this.form= this.fb.group({
TreatmentAntibiotics: ['', [Validators.required]],
})}changeAntibotics(event: any){
if(event.value==5){
this.addControl(['AnyOtherAntibiotics']);
}else{
this.removeControl(['AnyOtherAntibiotics']);
}
this.form.updateValueAndValidity();
}
removeControl(names: Array<string>){
for(let i=0;i<names.length;i++){
if(this.form.controls[names[i]])
this.form.removeControl(names[i]);
}
}addControl(names: Array<string>){
for(let i=0;i<names.length;i++){
if(!this.form.controls[names[i]]){
this.form.addControl(names[i],new FormControl(''));
}
}
}
I have made one common function of addcontrol where I check if this control exists in the form if its exist then don't need to do anything but if it won’t exist then add that
Similarly in the removeControl function, check if the control exists in the form if it exists then remove from the form otherwise leave it.
If I need to add Validator too, then
this.form.controls[type].setValidators([Validators.required, and so on]);
Also, I have called updateValueAndValidity so that form knows and validates accordingly.
In the HTML
<div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="space-between" *ngIf="form.value.TreatmentAntibiotics==5 && form.controls.AnyOtherAntibiotics">
<mat-label></mat-label>
<mat-form-field appearance="outline" fxFlex="40">
<input matInput placeholder="Any Other Antibiotics" formControlName="AnyOtherAntibiotics">
</mat-form-field>
</div>
The other thing, we generally do like need to add validation once it entered value, or in other words, add validation for the optional field.
We can do this by 2 methods, use the form valueChanges method or with the change function
HTML
<div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="space-between">
<mat-form-field appearance="outline" fxFlex="49">
<mat-label>Mobile Number</mat-label>
<input matInput formControlName="ContactMobile" (change)="addValidation('ContactMobile', 'mobileValidation')">
<mat-error *ngIf="form.get('ContactMobile').hasError('invalidMobile')">
Mobile Number is not valid
</mat-error>
</mat-form-field>
</div>
TS
addValidation(type: string, validation: any){
if(this.form.value[type]){
this.form.controls[type].setValidators([CommonValidations[validation]]);
this.form.controls[type].updateValueAndValidity();
}else{
this.form.controls[type].setErrors(null);
this.form.updateValueAndValidity();
}
}
If we don’t do updateValueAndValidity for particular control field while adding then it won’t work the first time, when we enter the field and wrote some text it won’t work and when we again enter the field then the validation works, so remember to add updateValueAndValidity for particular control field
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';private _unsubscribeAll: Subject<any>;
ngOnInit() {
this._unsubscribeAll = new Subject();
this.form = this.fb.group({
ContactMobile: [''],
})this.form.get('ContactMobile').valueChanges
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
if(this.form.value[type]){ this.form.controls[type].setValidators([CommonValidations.mobileValidation]);
this.form.controls[type].updateValueAndValidity();
}else{
this.form.controls[type].setErrors(null);
this.form.updateValueAndValidity();
}
});
}
ngOnDestroy(): void{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
I use subscription and takeuntil so unsubscribe from all the subscriptions when the component will destroyed
Happy Angular Validation 😊😊😊