Document global form application

master
Kevin C. Coram 2019-12-31 13:53:42 -08:00
parent cd7644a767
commit 1903b6f5c7
Signed by: kevin
GPG Key ID: 0342351B3D61AD35
1 changed files with 117 additions and 0 deletions

View File

@ -1 +1,118 @@
# Parent Component Creates Form and Passes Form Controls Into Child Components
An alternative approach to refactoring a component into child sub-components is to make the parent component be responsible for creating the entire Reactive Form, and to pass the appropriate form controls into the children. By also refactoring the logic for creating the form into a builder method in a separate service, the parent control's logic and template become almost as simple as in the [Own Form Controls](../parent-form/README.md) application:
```typescript
export class AppComponent implements OnInit, OnDestroy {
contact: Contact;
form: FormGroup;
private subscription: Subscription;
constructor(
private service: ContactService,
private formService: ContactFormService,
) {}
public ngOnInit() {
this.subscription = this.service
.loadContact()
.subscribe((data: Contact) => {
this.contact = data;
this.form = this.formService.createForm(data);
});
}
}
```
```html
<form [formGroup]="form">
<nested-forms-name
[nameGroup]="form.get('name')"
></nested-forms-name>
<nested-forms-address-list
[addressArray]="form.get('addresses')"
></nested-forms-address-list>
</form>
```
While the templates for `nested-forms-name` and `nested-forms-address-list` using this approach are almost identical to the templates in the _Own Form Controls_ example, the typescript code is even simpler:
```typescript
@Component({
selector: 'nested-forms-name',
templateUrl: './name.component.html',
styleUrls: ['./name.component.css']
})
export class NameComponent {
@Input() nameGroup: FormGroup;
}
```
## Form Builder Service
When looking at Reactive Forms through the lens of the _Model, View, Controller_ pattern, the `FormGroup` is the _Model_, and the HTML templating is the _View_. By using factory service methods to create the overall form structure, one can gain the benefits of encapsulation and composition while maintaining a strong separation between the _Model_ and the _View_.
```typescript
import { Injectable } from '@angular/core';
import { FormArray, FormBuilder, FormGroup } from '@angular/forms';
import { Contact, Name, Address } from '@nested-forms/contact';
@Injectable({
providedIn: 'root',
})
export class ContactFormService {
constructor(private fb: FormBuilder) {}
public createForm(model: Contact): FormGroup {
return this.fb.group({
name: this.createContactNameForm(model.name),
addresses: this.createContactAddressListForm(model.addresses),
});
}
public createContactNameForm(name: Name): FormGroup {
return this.fb.group({
firstName: [name ? name.firstName : ''],
lastName: [name ? name.lastName : ''],
middleName: [name ? name.middleName : ''],
prefix: [name ? name.prefix : ''],
suffix: [name ? name.suffix : ''],
})
}
public createContactAddressListForm(addresses: Address[]): FormArray {
const list: FormArray = this.fb.array([]);
if (addresses) {
addresses.forEach(addr => {
list.push(this.createContactAddressForm(addr));
});
}
return list;
}
public createContactAddressForm(addr: Address): FormGroup {
return this.fb.group({
line1: [addr ? addr.line1 : ''],
line2: [addr ? addr.line2 : ''],
city: [addr ? addr.city : ''],
state: [addr ? addr.state : ''],
postalCode: [addr ? addr.postalCode : ''],
});
}
}
```
## Pros
- Clean separation between _Model_ and _View_
- The parent component is easy to understand and maintain
- The child components are likewise easy to understand and maintain
- Encapsulation and composition are provided by the factory methods
## Cons
- Having a service with factory methods adds complexity to the application