diff --git a/apps/parent-form/README.md b/apps/parent-form/README.md index d5dab4d..eec92b7 100644 --- a/apps/parent-form/README.md +++ b/apps/parent-form/README.md @@ -1 +1,83 @@ # Components Creating Own Form Controls + +When a component becomes sufficiently complex, or the developer wishes to be able to reuse parts of it elsewhere, the component can be refactored into sub-components. One approach to binding such sub-components to their containing parent component is to pass the parent component's `FormGroup` in as an `@Input` parameter. Additionally, the data that each child sub-component needs is passed into an `@Input`. The children create their own `FormControls` as needed, and add them to the parent `FormGroup` provided to them. This approach greatly simplifies the code and template of the parent component: + +```typescript +export class AppComponent implements OnInit, OnDestroy { + contact: Contact; + form: FormGroup; + + private subscription: Subscription + + constructor(private fb: FormBuilder, private service: ContactService) { + this.form = this.fb.group({}); + } + + public ngOnInit() { + this.subscription = this.service.loadContact().subscribe((data: Contact) => { + this.contact = data; + }); + } +} +``` + +```html +
+``` + +The `nested-forms-name` component is responsible for creating the form controls binding to the Contact's name, and the `nested-forms-address-list` component is responsible for iterating over the Contact's addresses and binding to them using the `nested-forms-address` (singular) component. For example, the `nested-forms-name` would be implented as so: + +```typescript +@Component({ + selector: 'nested-forms-name', + templateUrl: './name.component.html', + styleUrls: ['./name.component.css'] +}) +export class NameComponent implements OnInit { + + @Input() name: Name; + @Input() parent: FormGroup; + + group: FormGroup; + + constructor(private fb: FormBuilder) { + } + + ngOnInit() { + this.group = this.fb.group({ + firstName: new FormControl(this.name ? this.name.firstName : ''), + lastName: new FormControl(this.name ? this.name.lastName : ''), + middleName: new FormControl(this.name ? this.name.middleName : ''), + prefix: new FormControl(this.name ? this.name.prefix : ''), + suffix: new FormControl(this.name ? this.name.suffix : ''), + }); + + if (this.parent) { + this.parent.addControl('name', this.group); + } + } +} +``` + +Calling `this.parent.addControl(....)` is what ensures that the controls created in the child component are made part of the over-all form. + +## Pros + +- The parent component is easy to understand and maintain +- Each child component encapsulates its form controls and template +- The child components can easily be re-used in other "parent" components + +## Cons + +- The creation of the form controls is tightly coupled with the templates +- Since each child component encapsulates its form controls, the overall shape of the form data is not always clear +