app.module.ts
import { BrowserModule } from'@angular/platform-browser';
import { NgModule } from'@angular/core';
import { FormsModule, ReactiveFormsModule } from'@angular/forms';
import { AppComponent } from'./app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, ReactiveFormsModule],
providers: [],
bootstrap: [AppComponent]
})
exportclassAppModule {}
app.component.ts
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']
})
exportclassAppComponentimplementsOnInit {
publicform: FormGroup;
publiccontactList: FormArray;
// returns all form groups
under contacts
getcontactFormGroup() {
returnthis.form.get('contacts') asFormArray;
}
constructor(privatefb: FormBuilder) {}
ngOnInit() {
this.form = this.fb.group({
name: [null, Validators.compose([Validators.required])],
organization: [null],
contacts:this.fb.array([this.createContact()])
});
// set contactlist to this
field
this.contactList = this.form.get('contacts') asFormArray;
}
// contact formgroup
createContact(): FormGroup {
returnthis.fb.group({
type: ['email', Validators.compose([Validators.required])], // i.e Email, Phone
name: [null, Validators.compose([Validators.required])], // i.e. Home, Office
value: [null, Validators.compose([Validators.required, Validators.email])]
});
}
// add a contact form group
addContact() {
this.contactList.push(this.createContact());
}
// remove contact from group
removeContact(index) {
// this.contactList =
this.form.get('contacts') as FormArray;
this.contactList.removeAt(index);
}
// triggered to change validation
of value field type
changedFieldType(index) {
letvalidators = null;
if (this.getContactsFormGroup(index).controls['type'].value === 'email') {
validators = Validators.compose([Validators.required, Validators.email]);
}
else {
validators = Validators.compose([
Validators.required,
Validators.pattern(newRegExp('^\\+[0-9]?()[0-9](\\d[0-9]{9})$')) // pattern for validating international phone number
]);
}
this.getContactsFormGroup(index).controls['value'].setValidators(
validators
);
this.getContactsFormGroup(index).controls['value'].updateValueAndValidity();
}
// get the formgroup under
contacts form array
getContactsFormGroup(index): FormGroup {
// this.contactList =
this.form.get('contacts') as FormArray;
constformGroup = this.contactList.controls[index] asFormGroup;
returnformGroup;
}
// method triggered when form is submitted
submit() {
console.log(this.form.value);
}
}
app.component.html
<divclass="container
p-3">
<divclass="row">
<divclass="col-12">
<form[formGroup]="form"(submit)="submit()">
<divclass="card">
<divclass="card-header">User Profile</div>
<divclass="card-body">
<divclass="row">
<divclass="form-group
col-3">
<label>Name</label>
<inputclass="form-control"formControlName="name"type="text"placeholder="Name">
<spanclass="text-danger"
*ngIf="form.controls['name'].touched
&&form.controls['name'].hasError('required')">
Name is required! </span>
</div>
<divclass="form-group
col-3">
<label>Designation</label>
<inputclass="form-control"formControlName="organization"type="text"placeholder="Designation">
</div>
<divclass="form-group
col-3">
<label>Subject</label>
<inputclass="form-control"formControlName="organization"type="text"placeholder="Subject">
</div>
<divclass="form-group
col-3">
<label>Classes</label>
<inputclass="form-control"formControlName="organization"type="text"placeholder="Classes">
</div>
<!--
<div
class="bs-example">
<div
class="btn-group btn-group-toggle"
data-toggle="buttons">
<label class="btnbtn-primary">
<input
type="radio" name="options"
autocomplete="off"> Option A
</label>
<label
class="btnbtn-primary active">
<input
type="radio" name="options" autocomplete="off"
checked> Option B
</label>
<label
class="btnbtn-primary">
<input
type="radio" name="options"
autocomplete="off"> Option C
</label>
</div>
</div> -->
</div>
</div>
<divclass="card-header">Contact Information</div>
<divclass="card-body"formArrayName="contacts">
<divclass="row">
<divclass="col-6"*ngFor="let
contact of contactFormGroup.controls; let i = index;">
<div[formGroupName]="i"class="row">
<divclass="form-group
col-6">
<label>Type of Contact</label>
<select(change)="changedFieldType(i)"class="form-control"formControlName="type"type="text">
<optionvalue="email">Email</option>
<optionvalue="phone">Phone</option>
</select>
</div>
<divclass="form-group
col-6">
<label>Branch Name</label>
<inputclass="form-control"formControlName="name"type="text"placeholder="Branch
Name">
<spanclass="text-danger"
*ngIf="getContactsFormGroup(i).controls['name'].touched
&&getContactsFormGroup(i).controls['name'].hasError('required')">
Label is required! </span>
</div>
<divclass="form-group
col-12">
<label>Email/Phone No</label>
<inputclass="form-control"formControlName="value"type="text"placeholder="Email/Phone
No">
<spanclass="text-danger"
*ngIf="getContactsFormGroup(i).controls['value'].touched
&&getContactsFormGroup(i).controls['value'].hasError('required')">
Email/Phone no is
required! </span>
<spanclass="text-danger"
*ngIf="getContactsFormGroup(i).controls['value'].touched
&&getContactsFormGroup(i).controls['value'].hasError('email')">
Email is not valid! </span>
<spanclass="text-danger"
*ngIf="getContactsFormGroup(i).controls['value'].touched
&&getContactsFormGroup(i).controls['value'].hasError('pattern')">
Phone no. is not valid! </span>
</div>
<divclass="form-group
col-12">
<label><b>Time</b> : </label>
<buttonclass="btn">8:30am to 12:30pm</button>
<buttonclass="btn">1:30pm to 4:30pm</button>
</div>
</div>
<divclass="form-group
col-12 text-right">
<buttonclass="btnbtn-primary
m-1"type="button"(click)="addContact()"> Add Form </button>
<buttonclass="btnbtn-danger"type="button"(click)="removeContact(i)"> Remove </button>
</div>
</div>
</div>
</div>
<divclass="card-body">
<divclass="col-12
text-center">
<buttonclass="btnbtn-success
m-1"[disabled]="!form.valid"type="submit"> Save
User Profile </button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
Angular.json
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"angular-dynamic-forms-reactive-forms": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss"
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/angular-dynamic-forms-reactive-forms",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
"src/styles.scss",
"node_modules/bootstrap/scss/bootstrap.scss"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "angular-dynamic-forms-reactive-forms:build"
},
"configurations": {
"production": {
"browserTarget": "angular-dynamic-forms-reactive-forms:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "angular-dynamic-forms-reactive-forms:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": ["src/styles.scss"],
"scripts": [],
"assets": ["src/favicon.ico", "src/assets"]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
"exclude": ["**/node_modules/**"]
}
}
}
},
"angular-dynamic-forms-reactive-forms-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "angular-dynamic-forms-reactive-forms:serve"
},
"configurations": {
"production": {
"devServerTarget": "angular-dynamic-forms-reactive-forms:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": ["**/node_modules/**"]
}
}
}
}
},
"defaultProject": "angular-dynamic-forms-reactive-forms"
}
Output
Image-1
Image-2
Onclick “Add Form” button display
additional add Form