SSOT form with two-way data binding
6 years ago
Angular
Angular 7
JavaScript
CodePen

Taking advantage of Angular's two-way data binding feature, I further simplify the Form Container component. It is now supports the main feature of Angular, the two way data binding. Using this feature, less things to be manually updated on using it. Less code, easier to undestand, and simpler to maintain.
Firstly, below are two example forms. These forms do not contain any much process in it. Kind of a presentation layer for the form.
First form example
@Component({
selector: 'my-form',
template: `
<h3>Profile</h3>
<form [formGroup]="form">
<label><span>First Name</span><input type="text" formControlName="firstName" required></label>
<label><span>Last Name</span><input type="text" formControlName="lastName" required></label>
<label><span>Position</span><input type="text" formControlName="position"></label>
</form>
`,
styles:[`form>label{display:block;}form > label>span{display:block;font-size: 10px;}`]
})
class MyForm {
@Input() form: FormGroup
@Output() formChange: EventEmitter = new EventEmitter()
constructor() {
}
ngOnInit() {
this.formChange.emit(this.form)
}
onChanges(): void {
console.log('MyForm > onChanges', this.form.value)
this.form.valueChanges.subscribe(value=>{
this.formChange.emit(this.form)
})
}
}
Second form example
@Component({
selector: 'my-address-form',
template: `
<h3>Address</h3>
<form [formGroup]="form">
<div formGroupName="address">
<label><span>Unit #</span><input type="text" formControlName="unit"></label>
<label><span>Street</span><input type="text" formControlName="street"></label>
<label><span>City</span><input type="text" formControlName="city"></label>
<label><span>Region</span><input type="text" formControlName="region"></label>
<label><span>State</span><input type="text" formControlName="state"></label>
<label><span>Country</span><input type="text" formControlName="country"></label>
</div>
</form>
`,
styles:[`form label{display:block;}form label>span{display:block;font-size: 10px;}`]
})
class AddressForm {
@Input() form: FormGroup
@Output() formChange: EventEmitter = new EventEmitter()
constructor() {
}
ngOnInit() {
this.formChange.emit(this.form)
}
onChanges(): void {
console.log('AddressForm > onChanges', this.form.value)
this.form.valueChanges.subscribe(value=>{
this.formChange.emit(this.form)
})
}
}
The Main form
Here is the main form that will contain other forms. Any changes in the children forms automatically trigger the changes in the parent component. Hence any process can be done here.
@Component({
selector: 'my-main',
template: `
<my-form [(form)]="form"></my-form>
<my-address-form [(form)]="form"></my-address-form>
<div><pre><code>{{form?.value|json}}</code></pre></div>
`
})
class Main {
private fb: FormBuilder = new FormBuilder()
form: FormGroup = this.fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
position: [''],
address: this.fb.group({
unit: [''],
street: [''],
city: [''],
region: [''],
state: [''],
country: [''],
}),
})
}
Usage
@Component({
selector: 'my-app',
template: `
<div class="container">
<h1>{{title}}</h1>
<p class="lead">{{lead}}</p>
<my-main></my-main>
</div>
`
})
class AppComponent {
title = `Angular 7: Forms Container`
lead = `Two-way binding the [(form)]. The main component has a single FormGroup object. The value of the object can be updated in child component.`
}
Updated
See in the codepen for preview and easy tinkering.