ReactiveForms Angular 2
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, FormArray, Validators } from '@angular/forms';
@Component({
selector: 'reactive-form',
templateUrl: './app/reactive/reactive-form.component.html'
})
export class ReactiveFormComponent implements OnInit {
form: FormGroup;
formErrors = {
name: '',
username: '',
addresses: [
{ city: '', country: '' }
]
};
validationMessages = {
name: {
required: 'Name is required.',
minlength: 'Name must be 3 characters.',
maxlength: 'Name can\'t be longer than 6 characters.'
},
username: {
required: 'Username is required.',
minlength: 'Username must be 3 characters.'
},
addresses: {
city: {
required: 'City is required.',
minlength: 'City must be 3 characters.'
},
country: {
required: 'Country is required.'
}
}
};
constructor(private fb: FormBuilder) {}
ngOnInit() {
// build the data model for our form
this.buildForm();
}
/**
* build the initial form
*/
buildForm() {
// build our form
this.form = this.fb.group({
name: ['', [Validators.minLength(3), Validators.maxLength(6)]],
username: ['', Validators.minLength(3)],
addresses: this.fb.array([
this.createAddress()
])
});
// watch for changes and validate
this.form.valueChanges.subscribe(data => this.validateForm());
}
/**
* validate the entire form
*/
validateForm() {
for (let field in this.formErrors) {
// clear that input field errors
this.formErrors[field] = '';
// grab an input field by name
let input = this.form.get(field);
if (input.invalid && input.dirty) {
// figure out the type of error
// loop over the formErrors field names
for (let error in input.errors) {
// assign that type of error message to a variable
this.formErrors[field] = this.validationMessages[field][error];
}
}
}
this.validateAddresses();
}
/**
* validate the addresses formarray
*/
validateAddresses() {
// grab the addresses formarray
let addresses = <FormArray>this.form.get('addresses');
// clear the form errors
this.formErrors.addresses = [];
// loop through however many formgroups are in the formarray
let n = 1;
while (n <= addresses.length) {
// add the clear errors back
this.formErrors.addresses.push({ city: '', country: '' });
// grab the specific group (address)
let address = <FormGroup>addresses.at(n - 1);
// validate that specific group. loop through the groups controls
for (let field in address.controls) {
// get the formcontrol
let input = address.get(field);
// do the validation and save errors to formerrors if necessary
if (input.invalid && input.dirty) {
for (let error in input.errors) {
this.formErrors.addresses[n - 1][field] = this.validationMessages.addresses[field][error];
}
}
}
n++;
}
}
createAddress() {
return this.fb.group({
city: ['', Validators.minLength(3)],
country: ['']
});
}
addAddress() {
let addresses = <FormArray>this.form.get('addresses');
addresses.push(this.createAddress());
}
removeAddress(i) {
let addresses = <FormArray>this.form.get('addresses');
addresses.removeAt(i);
}
processForm() {
console.log('processing', this.form.value);
}
}
<form (ngSubmit)="processForm()" [formGroup]="form">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" name="name" required
formControlName="name">
<span class="help-block" *ngIf="formErrors.name">
{{ formErrors.name }}
</span>
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" name="username" required
formControlName="username">
<span class="help-block" *ngIf="formErrors.username">
{{ formErrors.username }}
</span>
</div>
<!-- addresses -->
<div class="form-group" formArrayName="addresses">
<div *ngFor="let address of form.controls.addresses.controls;let i=index;">
<div class="panel panel-primary">
<div class="panel-heading">
Address #{{ i + 1 }}
<span *ngIf="form.controls.addresses.controls.length > 1" (click)="removeAddress(i)">
Remove
</span>
</div>
<div class="panel-body" [formGroupName]="i">
<div class="form-group">
<label>City</label>
<input type="text" class="form-control" formControlName="city" required>
<span class="help-block" *ngIf="formErrors.addresses[i].city">
{{ formErrors.addresses[i].city }}
</span>
</div>
<div class="form-group">
<label>Country</label>
<input type="text" class="form-control" formControlName="country" required>
<span class="help-block" *ngIf="formErrors.addresses[i].country">
{{ formErrors.addresses[i].country }}
</span>
</div>
</div>
</div>
</div>
</div>
<!-- add address button -->
<div class="text-right">
<a (click)="addAddress()" class="btn btn-info">Add Address</a>
</div>
<div class="form-group">
<button type="submit" class="btn btn-danger">Submit</button>
</div>
</form>