nested-forms/apps/baseline/README.md

2.7 KiB

Base Line - The Single component

The easiest way to create a simple Reactive Form is to use a single Angular component to build and display the form. In this example application, an asynchronous call to an API is simulated. The Contact object thus obtained is used to create and initialize a FormGroup using the Angular FormBuilder.

export class AppComponent implements OnInit, OnDestroy {
  form: FormGroup;

  private subscription: Subscription;

  public ngOnInit() {
    this.subscription = this.service
      .loadContact()
      .subscribe((data: Contact) => {
        this.form = this.createForm(data);
      });
  }

  public createForm(model: Contact): FormGroup {
    const name = model.name;

    const addresses: FormArray = this.fb.array([]);

    const group = this.fb.group({
      name: this.fb.group({
        firstName: [name ? name.firstName : ''],
        lastName: [name ? name.lastName : ''],
        middleName: [name ? name.middleName : ''],
        prefix: [name ? name.prefix : ''],
        suffix: [name ? name.suffix : ''],
      }),
      addresses: addresses,
    });

    if (model.addresses) {
      model.addresses.forEach(addr => {
        addresses.push(
          this.fb.group({
            line1: [addr ? addr.line1 : ''],
            line2: [addr ? addr.line2 : ''],
            city: [addr ? addr.city : ''],
            state: [addr ? addr.state : ''],
            postalCode: [addr ? addr.postalCode : ''],
          }),
        );
      });
    }

    return group;
  }

  get addresses(): FormArray {
    return this.form.get('addresses') as FormArray;
  }
}

The component's template remders input controls for the Contact's name, and iterates over the array of addresses to render controls to edit each one.

<form *ngIf="form" [formGroup]="form">
  <ng-container formGroupName="name">
    <div>
      <label for="firstName">First Name: </label>
      <input name="firstName" formControlName="firstName">
    </div>
    <!-- etc for each attribute in the Contact name -->
  </ng-container>

  <ng-container formArrayName="addresses">
    <ng-container *ngFor="let addr of addresses.controls; let i=index">
      <!-- Note: the form group is bound to the index variable -->
      <ng-container [formGroupName]="i">
        <div>
          <label for="line1">Line 1: </label>
          <input name="line1" formControlName="line1">
        </div>
        <!-- etc for each attribute in the Address -->
      </ng-container>
    </ng-container>
  </ng-container>

</form>

Pros

  • All of the logic is in one place
  • The potential complexity of multiple components is avoided

Cons

  • The component and its template will become ever larger and more complex as the form grows
  • Little-to-no opportunity for code reuse