原文: https://appdividend.com/2019/12/16/angular-form-control-example/
--------------------------------------------
Angular FormControl is an inbuilt class that is used to get and set values and validation of the form control fields like <input> or <select>. The FormControl tracks the value and validation status of an individual form control. It can be used standalone as well as with a parent form.
Types of Angular Forms
There are two types of form approaches in Angular.
- ReactiveForms
- Template-driven Forms
Reactive Forms
Creating a form using FormControl, FormGroup, and FormArray are said to be reactive forms. They use the ng module as ReactiveFormsModule.
3.9MFormControl:
FormControl is the class that is used to get and set values and validation of the form control such as <input> and <select> tag.
FormGroup:
FormGroup has the role to track the value and validity state of a group of FormControl.
FormArray:
FormArray tracks the value and validity state of the array of FormControl, FormGroup, or FormArray instances.
Template-Driven Form
Template Drive Forms are just Model Driven Form but driven by directives in the template versus code in the component.
In template-driven, we use directives to create the model. In model-driven, we generate a model on the component and then use directives to map elements in the template to our form model.
Angular FormControl
FormControl is one of the three fundamental building blocks of Angular forms, along with FormGroup and FormArray. It extends the AbstractControl class that implements most of the base functionality for accessing the value, validation status, user interactions, and events.
Sponsored Content
If you are confused with FormControl, FormGroup, FormArray, and Validators class, then this article will help you to understand how they can work together to build awesome angular form.
For every form control such as text, checkbox, radio button, we need to create the instance of FormControl in our class.
For example, let’s say we need to create an instance of the name field.
name = new FormControl();
In our HTML template, you can use the following code.
<input [formControl]="name">
Okay, let’s take a basic example.
First, create a new angular project.
Then import the ReactiveFormsModule inside the app.module.ts file.
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
So, we have imported the ReactiveFormsModule and add in the imports array.
The next step is to write the following code inside the app.component.ts file.
// app.component.ts
import { Component } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = new FormControl('', [Validators.required]);
}
We have imported the FormControl and Validators class inside the app.component.ts file and created an instance of FormControl called name.
That means, now we track the name field from HTML form.
Write the following code inside an app.component.html file.
<!-- app.component.html -->
<div>
<input [formControl]="name">
<label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required </label>
</div>
Also, we have put if a condition that says that if the name field is invalid, then it will display the error.
In our case, if it is empty, then it will show the error, and it is not, then it will disappear.
Also, write the following code inside the app.component.css file.
.error{
color: red;
font-size: 15px;
}
Save the file and run the following command to start the angular dev server.
ng serve -o
You will see something like the following.
When you start typing the name, the error will disappear.
Set Default value in FormControl
We can set a default value to our form control bypassing the value while instantiating a FormControl in our class. Update the following code inside the app.component.ts file.
// app.component.ts
name = new FormControl('The Weeknd', [Validators.required]);
Save the file, and you will see the textbox filled with “The Weeknd“.
Get value in FormControl.
We can get the value of a FormControl by using the value property on the instance of FormControl in our class. Update the following code inside the app.component.ts file.
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
name = new FormControl('The Weeknd', [Validators.required]);
ngOnInit() {
console.log(this.name.value);
}
}
Save the file, and inside the console tab of the browser, you will see that The Weeknd is logged.
So the value property fetches the value of the name FormControl.
Set value in FormControl
If a user has entered the new value in UI, our FormControl instance will be updated with the new value.
Now to set a value to a FormControl at run time, we need to call the setValue() method on the instance of FormControl in the class.
Write the following code inside the app.component.ts file.
// app.component.ts
import { Component } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = new FormControl('The Weeknd', [Validators.required]);
setNameValue() {
this.name.setValue('Ankit');
}
}
In this code, we have defined the setNameValue() function, which sets the value Ankit when the user fires an event like onchange or click event on the button.
We are taking a button, so we need also to update the app.component.html file.
<!-- app.component.html -->
<div>
<input [formControl]="name">
<label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required </label>
<div>
<button (click)="setNameValue()">Set value</button>
</div>
</div>
Save the file, and now, when you click on the Set value button, you will see the ‘Ankit’ inside the textbox.
FormControl with FormGroup using FormControlName
FormGroup tracks the value and validity state of a group of FormControl instances. FormGroup is one of the three fundamental building blocks used to define the forms in Angular, along with FormControl and FormArray.
The FormGroup aggregates the values of each child FormControl into one object, with each control name as a key. It calculates its status by reducing the status values of its children.
For example, if one of the controls in a group is invalid, the entire group becomes invalid. When instantiating a FormGroup, pass in a collection of child controls as the first argument. The key for each child registers the name for the control.
Let’s add two more fields. Write the following code inside the app.component.ts file.
// app.component.ts
import { Component } from '@angular/core';
import { FormControl, Validators, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
angForm = new FormGroup({
name: new FormControl('Krunal', Validators.maxLength(10)),
age: new FormControl(26, Validators.required),
college: new FormControl('VVP College'),
});
onFormSubmit(): void {
console.log('Name:' + this.angForm.get('name').value);
console.log('Age:' + this.angForm.get('age').value);
console.log('College:' + this.angForm.get('college').value);
}
}
First, we have imported FormGroup module from Angular forms and then created an instance of FormGroup and passed all the three fields and created its FormControl instances.
The instance of FormControl created in the class has been used in HTML using angular formControlName that syncs the FormControl value with HTML form control.
The [formGroup] is the FormGroupDirective that binds existing FormGroup to a DOM element.
When the form is submitted, we can access form values as follows.
this.angForm.get('name').value
So, when the user submits the form, we will get all the three form field’s values inside the console log.
Angular FormControl Validation With FormGroup
Write the following code inside the app.component.html file.
// app.component.ts
import { Component } from '@angular/core';
import { FormControl, Validators, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
angForm = new FormGroup({
name: new FormControl('', Validators.required),
age: new FormControl('', Validators.required),
college: new FormControl('', Validators.required),
});
get name(): any {
return this.angForm.get('name');
}
get age(): any {
return this.angForm.get('age');
}
get college(): any {
return this.angForm.get('college');
}
onFormSubmit(): void {
console.log('Name:' + this.angForm.get('name').value);
console.log('Age:' + this.angForm.get('age').value);
console.log('College:' + this.angForm.get('college').value);
}
}
To validate a particular form control, we need to get the value of that form control.
For example, to validate the name, age, and college FormControl, we need to create a method in our class as above.
get name(): any {
return this.angForm.get('name');
}
get age(): any {
return this.angForm.get('age');
}
get college(): any {
return this.angForm.get('college');
}
Now, write the following code inside the app.component.html file.
<!-- app.component.html -->
<form [formGroup] = "angForm" (ngSubmit)="onFormSubmit()">
<input formControlName="name" />
<label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required. </label>
<input formControlName="age" />
<label *ngIf="age.invalid" [ngClass] = "'error'"> Age is required. </label>
<input formControlName="college" />
<label *ngIf="college.invalid" [ngClass] = "'error'"> College is required. </label>
<div>
<button type="submit">Send</button>
</div>
</form>
So, now in the *ngif condition, we can access using that function name as an object name directly and call various properties on that object like an invalid, valid, pending, pristine, dirty, untouched, touched.
Save the file and go to the browser and you will see something like this.
FormControl with FormArray and FormControlName
In this section, we will use FormControl with FormArray and FormGroup using FormControlName.
In our angular application, FormArray is used when we want to dynamically generate form controls such as <input> and <select>.
Define names FormArray inside the app.component.ts file.
// app.component.ts
import { FormControl, FormGroup, FormArray, Validators } from '@angular/forms';
get names(): FormArray {
return this.angForm.get('names') as FormArray;
}
Next, we need to aggregate using FormGroup to names FormArray. Write the following code inside the app.component.ts file to do that.
// app.component.ts
angForm = new FormGroup({
names: new FormArray([
new FormControl('', Validators.required),
new FormControl('', Validators.required),
])
});
In the above code, we have created an array of FormControl instances.
We will iterate it in our UI. Write the following code inside the app.component.html file.
<div formArrayName="names">
<div *ngFor="let name of names.controls; index as idx">
<input [formControlName]="idx" placeholder="Enter a Name">
<label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required. </label>
</div>
</div>
When we submit the form, we can fetch values as given below.
Write the following code inside the app.component.ts file.
// app.component.ts
onFormSubmit(): void {
for(let i = 0; i < this.names.length; i++) {
console.log(this.names.at(i).value);
}
}
On the instance of FormArray, i.e., names, we will call controls that will return an array of FormControl instances. Now to add a form control at run time, we need to use the push() method of FormArray.
We are also adding validation while creating FormControl instances.
// app.component.ts
addNameField() {
this.names.push(new FormControl('', Validators.required));
}
We can remove the form control at run time; we need to use the removeAt() method of FormArray.
// app.component.ts
deleteNameField(index: number) {
this.names.removeAt(index);
}
So, our app.component.ts file looks like this.
// app.component.ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, FormArray, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
angForm = new FormGroup({
names: new FormArray([
new FormControl('', Validators.required),
new FormControl('', Validators.required),
])
});
get names(): FormArray {
return this.angForm.get('names') as FormArray;
}
addNameField() {
this.names.push(new FormControl('', Validators.required));
}
deleteNameField(index: number) {
this.names.removeAt(index);
}
onFormSubmit(): void {
for(let i = 0; i < this.names.length; i++) {
console.log(this.names.at(i).value);
}
}
}
Now, write our final code inside the app.component.html file.
<!-- app.component.html -->
<form [formGroup] = "angForm" (ngSubmit)="onFormSubmit()">
<div formArrayName="names">
<div *ngFor="let name of names.controls; index as idx">
<input [formControlName]="idx" placeholder="Enter a Name">
<label *ngIf="name.invalid" [ngClass] = "'error'"> Name is required. </label>
<button (click)="deleteNameField(idx)">Delete</button>
</div>
</div>
<div>
<button type="submit">Send</button>
<button type="button" (click)="addNameField()">Add More Names</button>
</div>
</form>
Save the file, and you will see the following.
Now, when you start typing your name at a particular textbox, for that specific textbox, the error will disappear.
When the user submits the form, we will get all the dynamically added textbox values.
Conclusion
Angular FormControl class tracks and control the values of Form Fields. It can set and get values. Using FormArray, you can add dynamic fields as much as possible, and it becomes effortless in Angular 9.
You can find more about FormControl in Angular documentation.
Finally, Angular 9 FormControl Example is over.