Kevin C. Coram be94a48b8a | ||
---|---|---|
.. | ||
src | ||
README.md | ||
browserslist | ||
jest.config.js | ||
tsconfig.app.json | ||
tsconfig.json | ||
tsconfig.spec.json | ||
tslint.json |
README.md
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:
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;
});
}
}
<form [formGroup]="form">
<nested-forms-name
[name]="contact.name"
[parent]="form"
></nested-forms-name>
<nested-forms-address-list
[addresses]="contact.addresses"
[parent]="form"
></nested-forms-address-list>
</form>
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:
@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, to the point that if a child component is not rendered for some reason, the form controls won't exist either.
- Since each child component encapsulates its form controls, the overall shape of the form data is not always clear