|
|
@@ -0,0 +1,87 @@ |
|
|
|
# Parent Component Creates Form ; Child Components Define Structure |
|
|
|
|
|
|
|
Another approach for refactoring a component into child sub-components where the parent component is responsible for creating the entre Reactive Form would be to define static factory methods within each child component rather than within a full-fledged service. As with the [Parent Component Creates Form and Passes Form Controls Into Child Components (Global Form)](../global-form/README.md) approach, the appropriate form controls would be passed into the children. |
|
|
|
|
|
|
|
In many ways, this approach is a hybrid between the Parent Form and Global Form approaches. |
|
|
|
|
|
|
|
```typescript |
|
|
|
export class AppComponent implements OnInit, OnDestroy { |
|
|
|
contact: Contact; |
|
|
|
form: FormGroup; |
|
|
|
|
|
|
|
private subscription: Subscription; |
|
|
|
|
|
|
|
constructor(private service: ContactService, private fb: FormBuilder) {} |
|
|
|
|
|
|
|
public ngOnInit() { |
|
|
|
this.subscription = this.service |
|
|
|
.loadContact() |
|
|
|
.subscribe((data: Contact) => { |
|
|
|
this.contact = data; |
|
|
|
this.form = this.fb.group({ |
|
|
|
name: NameComponent.buildForm(data.name), |
|
|
|
addresses: AddressListComponent.buildForm(data.addresses), |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
The HTML templating will be identical to the Global Form approach. |
|
|
|
|
|
|
|
## Static Form Builder Methods |
|
|
|
|
|
|
|
Rather than having a separate factory service, this approach uses static methods on each of the child sub-classes. This approach intentionally couples the logic for creating a sub-form structure with the component that would display it, keeping the logic in one place rather than separating it between components and an otherwise unrelated service. The rule-of-thumb in this approach is that the component which needs to display the form to a user will best know what the structure of that form needs to be. |
|
|
|
|
|
|
|
### Name Component |
|
|
|
|
|
|
|
```typescript |
|
|
|
static buildForm(name: Name): FormGroup { |
|
|
|
return new FormGroup({ |
|
|
|
firstName: new FormControl(name ? name.firstName : ''), |
|
|
|
lastName: new FormControl(name ? name.lastName : ''), |
|
|
|
middleName: new FormControl(name ? name.middleName : ''), |
|
|
|
prefix: new FormControl(name ? name.prefix : ''), |
|
|
|
suffix: new FormControl(name ? name.suffix : ''), |
|
|
|
}); |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
### Address List Component |
|
|
|
|
|
|
|
```typescript |
|
|
|
static buildForm(addresses: Address[]): FormArray { |
|
|
|
const list: FormArray = new FormArray([]); |
|
|
|
|
|
|
|
if (addresses) { |
|
|
|
addresses.forEach(addr => { |
|
|
|
list.push(AddressComponent.buildForm(addr)); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
return list; |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
### Address Component |
|
|
|
|
|
|
|
```typescript |
|
|
|
static buildForm(addr: Address): FormGroup { |
|
|
|
return new FormGroup({ |
|
|
|
line1: new FormControl(addr ? addr.line1 : ''), |
|
|
|
line2: new FormControl(addr ? addr.line2 : ''), |
|
|
|
city: new FormControl(addr ? addr.city : ''), |
|
|
|
state: new FormControl(addr ? addr.state : ''), |
|
|
|
postalCode: new FormControl(addr ? addr.postalCode : ''), |
|
|
|
}); |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
## Pros |
|
|
|
|
|
|
|
- The child components encapsulate the form controls and their display, while keeping the form creation logic separate from the actual template rendering |
|
|
|
- The child components can easily be re-used |
|
|
|
|
|
|
|
## Cons |
|
|
|
|
|
|
|
- The overall shape of the form from the parent component's perspective is not always clear |