What is angular formbuilder?
FormBuilder
is in-build service class of angular reactive form. FormBuilder provides (group, control, array) methods to create FormGroup, FormControl, FormArray blocks that are instances of Angular Reactive Form.
Some of the advantages of FormBuilder
- Shortly creating instances of FormControl, FormGroup, or FormArray
- Reduce the repeatation of FormControl, FormGroup, FormArray class.
- Reduces the required code to build the complex forms
How to use angular formbuilder?
- Import ReactiveFormsModule module.
- Inject FormBuilder in component.
- Now create a form using formBuilder
FormBuilder control/FormControl
Control can be defined with [ ] symbol inside FormBulder group or array and that takes the first parameter as default value. and second as validation class or array of validation classes. example
["defaultValue", Validators.required] [54, [Validators.required, Validators.min(1)]] // Multiple validation
define with the method but inside FormGroup and FormArray, it’s not a good approach and not recommended
name: FormControl = this.formBuilder.control('', Validators.required)
Create productForm using FormBuilder step-by-step
Step-1 Setting up new project
Generate new angular project
ng new angular-reactive-formbuilder --routing=true --style=scss --skip-tests cd angular-reactive-formbuilder
That will generate a new angular project with routing, the style set to scss (available style CSS, SASS, SCSS, LESS), and skip test configuration.
Import ReactiveFormsModule modules
The reactive forms require the import ReactiveFormsModule
module. Update app.module.ts file, add ReactiveFormsModule module.
import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Step-2 Define productForm in component class
Edit app.component.ts file
import { Component, OnInit } from '@angular/core'; import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { categories: string[] = ['Accessories', 'Apparel', 'Footwear', 'Homewares', 'Audiobooks'] productForm!: FormGroup; constructor(private formBuilder: FormBuilder) {} ngOnInit(): void { this.productForm = this.formBuilder.group({ name: this.formBuilder.control('', Validators.required), price: ['', [Validators.required, Validators.min(1)]], description: ['',], category: ['', [Validators.required]], keywords: this.formBuilder.array([ ['', [Validators.required]], ['', [Validators.required]], ['', [Validators.required]], ]) }) } get keywordsControls(): any { return (<FormArray>this.productForm.get('keywords')).controls; } onFormSubmit(): void { const formData = this.productForm.value console.log(formData) // Call api post service here } }
let’s breakdown app.component.ts:
Product form has name, price, description, category as FormControl. and keywords as FormArray which also has three controls.
Don’t be confused about the name, price control declaration. Name, price both are the same as FormControl. I always use the price way, it’s shorts and the same.
keywordsControls provide keywords FormArray separately. and rest of OnFormSubmit is a form submit methods
Step-3 Create product form and bind in html
update app.component.html file
<div class="container"> <form [formGroup]="productForm" (ngSubmit)="onFormSubmit()"> <h3>Product Form</h3> <div class="input-group"> <input [class.border-danger]="productForm.get('name')?.touched && productForm.get('name')?.invalid" type="text" formControlName="name" placeholder="Name"> <div *ngIf="productForm.get('name')?.touched && productForm.get('name')?.hasError('required')" class="text-sm text-danger">Product name is required</div> </div> <div class="input-group"> <input [class.border-danger]="productForm.get('price')?.touched && productForm.get('price')?.invalid" type="email" formControlName="price" placeholder="Price"> <div *ngIf="productForm.get('price')?.touched && productForm.get('price')?.hasError('required')" class="text-sm text-danger">Price is required</div> <div *ngIf="productForm.get('price')?.touched && productForm.get('price')?.hasError('min')" class="text-sm text-danger">Min 1 required</div> </div> <div class="input-group"> <select formControlName="category" [class.border-danger]="productForm.get('number')?.touched && productForm.get('number')?.invalid"> <option [value]="''">Select Category</option> <option [value]="cat" *ngFor="let cat of categories">{{cat}}</option> </select> <div *ngIf="productForm.get('category')?.touched && productForm.get('category')?.hasError('required')" class="text-sm text-danger">Category is required</div> </div> <div class="input-group"> <textarea formControlName="description" id="" cols="30" rows="10" placeholder="Description"></textarea> </div> <hr> <h4>Keywords</h4> <div formArrayName="keywords"> <div *ngIf="keywordsControls && keywordsControls.length"> <div *ngFor="let keywordControl of keywordsControls; let i = index"> <div class="input-group"> <input [class.border-danger]="keywordControl.touched && keywordControl.invalid" [formControlName]="i" type="text" placeholder="keyword" /> <div *ngIf="keywordControl.touched && keywordControl.hasError('required')" class="text-sm text-danger">keyword Name is required</div> </div> <hr> </div> </div> </div> <button [disabled]="productForm.invalid" style="margin-top: 40px;" type="submit">Submit</button> </form> </div>
Step-4 Add minor css for UI form (optional)
CSS is totally UI representational. it does not affect angular ReactiveForm but Effect in HTML Form and HTML validation error message style
* { box-sizing: border-box; } .container { max-width: 400px; margin-left: auto; margin-right: auto; padding-top: 50px; } .text-sm { font-size: 80%; margin-top: 5px; } .border-danger { border-color: red; } .text-danger { color: red; } textarea, select, input { width: 100%; padding: 5px 12px; } .flex { display: flex; } .items-center { align-items: center; } .justify-end { justify-content: flex-end; } // form .input-group { margin-bottom: 10px; }
Angular FormBuilder official API ref https://angular.io/api/forms/FormBuilder