FormControl In Angular
In this article, We will learn what is FormControl and some of its attributes and methods. The particular HTML form element is set and tracked by FormControl. It is one of the angular forms' building blocks. FormArray and FormGroup are the other two.
What is FormControl
Take a look at a simple text input box.
First Name : <input type="text" name="firstname" />
As a developer, you'd like to know what the text box's current value is. You'd also like to know whether the value is correct. If the value(dirty) has been updated by the user or if it has remained unchanged. You want to be alerted if the user modifies the value.
The FormControl is an object that contains all of the data associated with a single input element. It keeps track of the value and status of each of these controls.
FormControl is merely a class. For each form field, a FormControl is produced. We may use our component class to refer to them and check their attributes and methods.
FormControl can be used to change the value of the Form field. Determine the current status of
Using FormControl
There are two methods for creating Angular Forms in Angular. The first is template-driven, whereas the second is Reactive Forms.
To use Angular forms, import the FormsModule (for template-driven forms) and ReactiveFormsModule (for Reactive Forms) from @angular/forms in your route module first.
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
Also, include it in the metadata for imports.
imports: [ BrowserModule, AppRoutingModule, FormsModule, ReactiveFormsModule ],
Reactive Forms
It is our obligation to design the Model use FormGroup, FormControl, and FormArray in the Reactive Forms methodology.
To use FormControl, we must first import it from the @angular/forms package.
import { FormGroup, FormControl, Validators } from '@angular/forms'
Then make the FormGroup at the top of the hierarchy. The collection of FormControl is the first argument to FormGroup. The FormControl method is used to add them, as seen below.
reactiveForm = new FormGroup({ firstname: new FormControl('',[Validators.required]), lastname: new FormControl(), email: new FormControl(), })
Alternatively, you can use the FormBuilder API.
this.reactiveForm = this.formBuilder.group({ firstname: ['',[Validators.required]], lastname: [''], email: [''], });
Use the formControlName directive to link the form element to the template, as illustrated below.
<form [formGroup]="reactiveForm" (ngSubmit)="onSubmit()" novalidate> <p> <label for="firstname">First Name </label> <input type="text" id="firstname" name="firstname" formControlName="firstname"> </p> <p> <label for="lastname">Last Name </label> <input type="text" id="lastname" name="lastname" formControlName="lastname"> </p> <p> <label for="email">Email </label> <input type="text" id="email" name="email" formControlName="email"> </p> <p> <button type="submit">Submit</button> </p> </form>
Template-driven forms
The FormControl is defined in the Template in template-driven forms. The top-level FormGroup is created by the <Form> directive. On each Form element, we use the ngModel directive, which automatically creates the FormControl object.
<form #templateForm="ngForm" (ngSubmit)="onSubmit(templateForm)" novalidate> <p> <label for="firstname">First Name</label> <input type="text" name="firstname" ngModel> </p> <p> <label for="lastname">Last Name</label> <input type="text" name="lastname" ngModel> </p> <p> <label for="email">Email </label> <input type="text" id="email" name="email" ngModel> </p> <p> <button type="submit">Submit</button> </p> </form>
To gain a reference to the FormModel in the Component class, use the viewChild. The top-level FormGroup is returned by the NgForm control property.
@ViewChild('templateForm',null) templateForm: NgForm;
Setting the value
setValue()
abstract setValue(value: any, options?: Object): void
To set a new value for the form control, we use the FormControl's setValue or patchValue methods. At the FormControl level, there is no difference between setValue and patchValue.
setEmail() { this.reactiveForm.get("email").setValue("sachin.tendulakar@gmail.com"); }; setEmail() { this.templateForm.control.get("email").setValue("sachin.tendulkar@gmail.com"); };
patchValue()
abstract patchValue(value: any, options?: Object): void
setEmail() { this.reactiveForm.get("email").setValue("sachin.tendulakar@gmail.com"); }; setEmail() { this.templateForm.control.get("email").setValue("sachin.tendulkar@gmail.com"); };
Two-way binding
In Template-driven forms, two-way data binding is the preferred method of keeping the component model in sync with the FormModel.
<p> <label for="firstname">First Name </label> <input type="text" id="firstname" name="firstname" [(ngModel)]="contact.firstname"> </p>
Finding the Value
value
value: any
The value returns the current FormControl value. It's in read-only mode. Use the setValue or patchValue methods to change the value of the control.
//reactive forms this.reactiveForm.get("firstname").value
//template driven forms this.templateForm.control.get("firstname").value
valueChanges
valueChanges: Observable<any>
When the value of a control changes, the component broadcasts the valueChanges event. The value may vary when the user edits the UI element or when the setValue/patchValue function is used programmatically. As indicated below, we can subscribe to it.
//reactive Forms this.fNameChange = this.reactiveForm.get("firstname").valueChanges.subscribe(x => { console.log(x); })
In template-driven forms, it's the same.
setTimeout(() => { this.fNameChange = this.templateForm.control.get("firstname").valueChanges.subscribe(x => { console.log(x); }) });
Control Status
The FormControl keeps track of the HTML Element to which it is bound's validation state. The following is a list of properties connected to status.
status
status: string
When the value of a form control changes, Angular performs validation checks. The control can have four possible states depending on the validation result.
VALID: All validity checks on the FormControl were passed.
INVALID: At least one validation check has failed for this control.
PENDING: This control is currently doing a validation check.
DISABLED: Validation checks are not performed on this control.
//reactive forms this.reactiveForm.get("firstname").status
//template driven forms this.templateForm.control.get("firstname").status
valid
valid: boolean
When a control has passed all of the validation checks and is not disabled, it is considered legitimate.
this.reactiveForm.get("firstname").valid
invalid
invalid: boolean
When a control fails one of the validation criteria but is not disabled, it is considered invalid.
this.reactiveForm.get("firstname").invalid
pending
pending: boolean
When a control is doing a validation check, it is considered pending.
this.reactiveForm.get("firstname").pending
disabled
disable: boolean
When the state of a control is Deactivated, it is disabled.
this.reactiveForm.get("firstname").disabled
enabled
enable: boolean
As long as the status is not DISABLED, control is enabled.
this.reactiveForm.get("firstname").disabled
pristine
pristine: boolean
If the user has not yet updated the value in the UI, the control is clean.
this.reactiveForm.get("firstname").pristine
dirty
dirty: boolean
If the user has changed the value in the UI, the control is dirty.
this.reactiveForm.get("firstname").dirty
touched
touched: boolean
If the control has been marked as touched, this is true. When a user triggers a blur event on a control, it is tagged as touched.
this.reactiveForm.get("firstname").touched
untouched
untouched: boolean
If the control hasn't been marked as touched, this is true. If the user has not yet triggered a blur event on a control, it is considered undisturbed.
this.reactiveForm. get("firstname"). untouched
Changing the Status
The following methods can be used to modify the status of the control programmatically.
When we alter the status of a control programmatically or via UI, the parent control's validity and value are calculated and updated as well. There may be occasions when you do not want this to occur. OnlySelf:true can be used in these situations to ensure that the parent control is not checked.
markAsTouched
This approach indicates that the control has been touched.
markAsTouched(opts: { onlySelf?: boolean; } = {}): void
onlySelf: Only this control is marked if true. If it is false, it will mark all of its direct ancestors as touched as well. False is the default value.
this.reactiveForm.get("firstname").markAsTouched() this.reactiveForm.get("firstname").markAsTouched({ onlySelf:true; })
markAllAsTouched
Syntax
markAllAsTouched(): void
The control, as well as all descendant controls, is marked as touched.
markAsUntouched
Syntax
markAsUntouched(opts: { onlySelf?: boolean; } = {}): void
The control is marked as undisturbed.
onlySelf: Only this control is marked as untouched if true. Mark all direct ancestors as unaffected if the information is inaccurate or not provided. False is the default value.
markAsDirty
Syntax
markAsDirty(opts: { onlySelf?: boolean; } = {}): void
The control is marked as filthy. When the value of a control is updated via the user interface, it becomes dirty.
onlySelf: If this is the case, only this control will be tagged as dirty; otherwise, all immediate ancestors will be marked as dirty. False is the default value.
markAsPristine
Syntax
markAsPristine(opts: { onlySelf?: boolean; } = {}): void
The control is marked as immaculate.
onlySelf: If this is the case, only this control will be designated as pristine; otherwise, all immediate ancestors will be tagged as pristine. False is the default value.
markAsPending
Syntax
markAsPending(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
The control is marked as pending. When the control is in the middle of doing a validation check, we label it as pending.
onlySelf: If true, only this control will be marked. Mark all direct ancestors if they are false or not provided. False is the default value.
emitEvent: The statusChanges observable produces an event with the most recent status the control is tagged pending whether true or not specified (the default). When this value is false, no events are generated.
disable
Syntax
disable(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
The control is turned off. This indicates the control is not subject to validity tests and is not included in any parent's aggregate value. Its current state is DISABLED.
onlySelf: If true, only this control will be marked. Mark all direct ancestors if they are false or not provided. The default value is false.
emitEvent: When the control is disabled, both the statusChanges and valueChanges observables emit events with the most recent status and value, whether true or not given (the default). When this value is false, no events are generated.
enable
Syntax
enable(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
Allows for control. This indicates that the control is included in validation checks and the parent's aggregate value. Its value and validators are used to recalculate its status.
onlySelf: If true, only this control will be marked. Mark all direct ancestors if they are false or not provided. False is the default value.
emitEvent: When the control is enabled, both the statusChanges and valueChanges observables broadcast events with the most recent status and value, whether true or not supplied (the default). When this value is false, no events are generated.
Status Change Event
statusChanges
Syntax
statusChanges: Observable<any>
By subscribing to the statusChanges event, we may subscribe to the statusChanges event. When the control's validity status is calculated, the event is triggered.
//Reactive Forms this.reactiveForm.get("firstname").statusChanges.subscribe(x => { console.log(x); })
//Template Driven Forms this.templateForm.control.get("firstname").statusChanges.subscribe(x => { console.log(x); })
Validation
Whether we use template-driven forms or reactive forms determines how we add validators.
Validators are added to Reactive forms when the controls are declared.
reactiveForm = new FormGroup({ firstname: new FormControl('',[Validators.required]), lastname: new FormControl(), email: new FormControl(), })
While in the template's template-driven forms
<p> <label for="firstname">First Name </label> <input type="text" id="firstname" name="firstname" ngModel required > </p>
updateValueAndValidity()
Syntax
updateValueAndValidity(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
The updateValueAndValidity method makes the form validate itself. This is useful when using setValidators and RemoveValidators to dynamically add and remove validators.
onlySelf: Only update this control if true. Update all direct ancestors if false or not specified. The default value is false.
emitEvent: When the control is updated, both the statusChanges and valueChanges observables broadcast events with the newest status and value, whether true or not supplied (the default). When this value is false, no events are generated.
//reactive forms this.reactiveForm.get("firstname").updateValueAndValidity(); //template driven forms this.templateForm.control.get("firstname").updateValueAndValidity();
setValidators() / setAsyncValidators()
The sync or async validators are added programmatically. This function will remove any sync or async validators that were previously installed.
Syntax
setValidators(newValidator: ValidatorFn | ValidatorFn[]): void setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[]): void
//Reactive Form setValidator() { this.reactiveForm.get("firstname").setValidators([Validators.required, Validators.minLength(5)]); this.reactiveForm.get("firstname").updateValueAndValidity(); } //Template driven forms setValidator() { this.templateForm.control.get("firstname").setValidators([Validators.required, Validators.minLength(5)]); this.templateForm.control.get("firstname").updateValueAndValidity(); }
clearValidators() / clearAsyncValidators()
Syntax
clearValidators(): void clearAsyncValidators(): void
All validators are cleared with clearValidators and clearAsyncValidators.
//reactive forms clearValidation() { this.reactiveForm.get("firstname").clearValidators(); this.reactiveForm.get("firstname").updateValueAndValidity(); } //template driven forms clearValidation() { this.templateForm.control.get("firstname").clearValidators(); this.templateForm.control.get("firstname").updateValueAndValidity(); }
errors()
Syntax
errors: ValidationErrors | null
If validation fails, this object contains any errors that are generated, or null if no errors are generated.
getErrors() { const controlErrors: ValidationErrors = this.reactiveForm.get("firstname").errors; if (controlErrors) { Object.keys(controlErrors).forEach(keyError => { console.log("firtname "+ ' '+keyError); }); } }
setErrors()
Syntax
setErrors(errors: ValidationErrors, opts: { emitEvent?: boolean; } = {}): void
Example
setErrors() { this.reactiveForm.get("firstname").setErrors( {customerror:'custom error'}); }
getError()
Syntax
getError(errorCode: string, path?: string | (string | number)[]): any
Error data for the control with the supplied URL is reported.
this.reactiveForm.getError("firstname") // this.reactiveForm.getError("address.pincode"); this.reactiveForm.getError(["address","pincode"]);
hasError
Syntax
hasError(errorCode: string, path?: string | (string | number)[]): boolean
Returns true if the control with the supplied path contains the stated error.
this.reactiveForm.hasError("firstname") // this.reactiveForm.hasError("address.pincode"); this.reactiveForm.hasError(["address","pincode"]);
Reset
Syntax
Syntax
abstract reset(value?: any, options?: Object): void
The control is reset. The default value can also be given.
this.reactiveForm.get("firstname").reset(''); this.reactiveForm.get("firstname").reset('test');
Conclusion
in this article, We learn what is FormControl and looked at the various methods and properties.
I hope this article helps you and you will like it.👍
If you have any doubt or confusion then free to ask in comment section.