You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Kevin C. Coram 1903b6f5c7
Document global form application
6 months ago
..
src Update form group name to conform to Name interface 10 months ago
README.md Document global form application 6 months ago
browserslist Generate global-form skeleton 10 months ago
jest.config.js Generate global-form skeleton 10 months ago
tsconfig.app.json Generate global-form skeleton 10 months ago
tsconfig.json Generate global-form skeleton 10 months ago
tsconfig.spec.json Generate global-form skeleton 10 months ago
tslint.json Generate global-form skeleton 10 months ago

README.md

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 application:

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);
      });
  }
}
<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:

@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.

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