Building Reusable Forms in Angular
Tags: angular, forms
Published: 2019-08-30 14:15:16

---
title: Building Reusable Forms in Angular
description: Learn how to create reusable and nestable forms in Angular.
keywords: Angular, Angular Forms, Reusable, Cory Rylan
tags: angular, forms
canonical_url: https://coryrylan.com/blog/building-reusable-forms-in-angular
published: true
---

This post is an modified excerpt chapter from my new EBook [Angular Form Essentials](https://angularforms.dev)

When building out large Angular applications likely, you will come across the use case of creating reusable Forms as well as nesting form components. In this post, we will cover how to build a reusable Angular form using the <a href="https://coryrylan.com/blog/angular-custom-form-controls-with-reactive-forms-and-ngmodel">`ControlValueAccessor`</a> API.

For our use case, we will have three forms we need to build. The first form will be a create password form that will have two fields, `password` and `confirmPassword`. The second form will be a user profile form with three fields, `firstName`, `lastName`, and `email`. Our last a final form will combine both the user profile form and the create password form into a single user sign up form.

We split the sign up form into the two smaller forms to allow the forms to be reusable in other parts of our application. For example, the password form can be used in the sign up form as well as a password reset form.

<img src="https://coryrylan.com/assets/images/posts/2019-07-24-building-reusable-forms-in-angular/reusable-forms-in-angular.png" bp="full-width float-center 8--max" alt="Example of Reusable Forms in Angular" />

In the image above, we see all three forms. Each form is highlighted with a different color. The blue form is the user profile form. The green form is the create password form, and the red form is the combined user sign up form. Let's start with the parent user sign up form.

```typescript
import { Component } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';

@Component({
  selector: 'app-reusable-forms-example',
  templateUrl: './reusable-forms-example.component.html',
  styleUrls: ['./reusable-forms-example.component.scss']
})
export class ReusableFormsExampleComponent {
  signupForm: FormGroup;

  constructor(private formBuilder: FormBuilder) {
    this.signupForm = this.formBuilder.group({
      password: [],
      profile: []
    });
  }

  submit() {
    console.log(this.signupForm.value);
  }
}
```

Our parent form is a standard reactive form using the `FormBuilder` service. Notice how we have only two control names, `password` and `profile`. Only two control names are needed as they represent a single subform control. Each of our form controls are nested reactive forms. Even though they are nested forms, the parent form sees them as just another form control.

```html
<form [formGroup]="signupForm" (ngSubmit)="submit()">
  <app-profile-form formControlName="profile"></app-profile-form>
  <app-password-form formControlName="password"></app-password-form>
  <button>Sign Up</button>
</form>
```

By having our subforms implement the `ControlValueAccessor` API, each subform is a stand-alone reusable form control. By making each subform a standalone control, it makes it easy to reuse, validate, and nest our custom forms in Angular.

## Sub Forms with Control Value Accessor

Let's take a look at the profile form to see how to implement it using the `ControlValueAccessor` API to make it reusable. Our profile form has three inputs, `firstName`, `lastName`, and `email`. In this form, the `email` input is required. Let's first start with the template.

```html
<div [formGroup]="form">
  <label for="first-name">First Name</label>
  <input formControlName="firstName" id="first-name" />

  <label for="last-name">Last Name</label>
  <input formControlName="lastName" id="last-name" />

  <label for="email">Email</label>
  <input formControlName="email" type="email" id="email" />
  <div *ngIf="emailControl.touched && emailControl.hasError('required')" class="error">
    email is required
  </div>
</div>
```

This form is a standard reactive form but notice that we don't use a `form` tag and instead use a `div`. We don't use a `form` tag because when we make this a custom control that we can embed into other forms and we cannot nest a `form` element in another `form`. In the TypeScript, we will create a reactive form using the `FormBuilder` as well as the <a href="https://coryrylan.com/blog/angular-custom-form-controls-with-reactive-forms-and-ngmodel">`ControlValueAccessor` API</a>.

```typescript
import { Component, forwardRef, OnDestroy } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-profile-form',
  templateUrl: './profile-form.component.html',
  styleUrls: ['./profile-form.component.scss']
})
export class ProfileFormComponent {
  form: FormGroup;

  get emailControl() {
    return this.form.controls.email;
  }

  constructor(private formBuilder: FormBuilder) {
    this.form = this.formBuilder.group({
      firstName: [],
      lastName: [],
      email: ['', Validators.required]
    });
  }
}
```

The profile form we create with the `FormBuilder` service. To make
the form reusable we will use the `ControlValueAccessor` to map the form to the parent form and relay updates such as value changes and validations updates.

```typescript
import { Component, forwardRef, OnDestroy } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder, FormGroup, Validators, FormControl, NG_VALIDATORS } from '@angular/forms';
import { Subscription } from 'rxjs';

// describes what the return value of the form control will look like
export interface ProfileFormValues {
  firstName: string;
  lastName: string;
  email: number;
}

@Component({
  selector: 'app-profile-form',
  templateUrl: './profile-form.component.html',
  styleUrls: ['./profile-form.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ProfileFormComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => ProfileFormComponent),
      multi: true,
    }
  ]
})
export class ProfileFormComponent implements ControlValueAccessor, OnDestroy {
  form: FormGroup;
  subscriptions: Subscription[] = [];

  get value(): ProfileFormValues {
    return this.form.value;
  }

  set value(value: ProfileFormValues) {
    this.form.setValue(value);
    this.onChange(value);
    this.onTouched();
  }

  get emailControl() {
    return this.form.controls.email;
  }

  constructor(private formBuilder: FormBuilder) {
    // create the inner form
    this.form = this.formBuilder.group({
      firstName: [],
      lastName: [],
      email: ['', Validators.required]
    });

    this.subscriptions.push(
      // any time the inner form changes update the parent of any change
      this.form.valueChanges.subscribe(value => {
        this.onChange(value);
        this.onTouched();
      })
    );
  }

  ngOnDestroy() {
    this.subscriptions.forEach(s => s.unsubscribe());
  }

  onChange: any = () => {};
  onTouched: any = () => {};

  registerOnChange(fn) {
    this.onChange = fn;
  }

  writeValue(value) {
    if (value) {
      this.value = value;
    }
  }

  registerOnTouched(fn) {
    this.onTouched = fn;
  }

  // communicate the inner form validation to the parent form
  validate(_: FormControl) {
    return this.form.valid ? null : { profile: { valid: false, }, };
  }
}
```

In our decorator, we register the component using `NG_VALUE_ACCESSOR` as well as using `NG_VALIDATORS` to have angular acknowledge that this form will self validate. By self-validating, we can have the form validate its inputs and then communicate the validation state to the parent form.

In the constructor, we listen for our inner form values and the trigger the control to update that the form value has changed.

```typescript
this.subscriptions.push(
  this.form.valueChanges.subscribe(value => {
    this.onChange(value);
    this.onTouched();
  })
);
```

We also want the parent form to be able to know if the profile form is valid or not. To do this, we implement a `validate()` method.

```typescript
validate(_: FormControl) {
  return this.form.valid ? null : { profile: { valid: false, } };
}
```

If the inner form is invalid, then we communicate back to the parent form
that the inner form is in an invalid state which will allow us to handle
validation at the parent level. Next, let's take a look at the Password form.

## Reusable Password Creation Form

The password form uses the same technique as our profile form. We will use the `FormBuilder` service as well as the `ControlValueAccessor` API.

```html
<div [formGroup]="form">
  <label for="password">Password</label>
  <input formControlName="password" type="password" id="password" />
  <div *ngIf="passwordControl.touched && passwordControl.hasError('required')" class="error">
    password is required
  </div>

  <label for="confirm-password">Confirm Password</label>
  <input formControlName="confirmPassword" type="password" id="confirm-password" />
  <div *ngIf="confirmPasswordControl.touched && confirmPasswordControl.hasError('required')" class="error">
    password is required
  </div>

  <div *ngIf="passwordControl.touched && confirmPasswordControl.touched && form.hasError('missmatch')" class="error">
    passwords do not match
  </div>
</div>
```

The Password form has two inputs, the password as well as the confirm password. The form will also use group validation to make sure that both inputs match correctly.

```typescript
import { Component, forwardRef, OnDestroy } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormGroup, FormBuilder, ControlValueAccessor, Validators, NG_VALIDATORS, FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';

import { matchingInputsValidator } from './validators';

export interface PasswordFormValues {
  password: string;
  confirmPassword: string;
}

@Component({
  selector: 'app-password-form',
  templateUrl: './password-form.component.html',
  styleUrls: ['./password-form.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => PasswordFormComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => PasswordFormComponent),
      multi: true,
    }
  ]
})
export class PasswordFormComponent implements ControlValueAccessor, OnDestroy {
  form: FormGroup;
  subscriptions: Subscription[] = [];

  get value(): PasswordFormValues {
    return this.form.value;
  }

  set value(value: PasswordFormValues) {
    this.form.setValue(value);
    this.onChange(value);
    this.onTouched();
  }

  get passwordControl() {
    return this.form.controls.password;
  }

  get confirmPasswordControl() {
    return this.form.controls.confirmPassword;
  }

  constructor(private formBuilder: FormBuilder) {
    this.form = this.formBuilder.group({
      password: ['', Validators.required],
      confirmPassword: ['', Validators.required]
    }, { validator: matchingInputsValidator('password', 'confirmPassword') });

    this.subscriptions.push(
      this.form.valueChanges.subscribe(value => {
        this.onChange(value);
        this.onTouched();
      })
    );
  }

  ngOnDestroy() {
    this.subscriptions.forEach(s => s.unsubscribe());
  }

  onChange: any = () => {};
  onTouched: any = () => {};

  registerOnChange(fn) {
    this.onChange = fn;
  }

  writeValue(value) {
    if (value) {
      this.value = value;
    }
  }

  registerOnTouched(fn) {
    this.onTouched = fn;
  }

  validate(_: FormControl) {
    return this.form.valid ? null : { passwords: { valid: false, }, };
  }
}
```

We define our form with the `FormBuilder` and then relay that information back to the parent.

```typescript
constructor(private formBuilder: FormBuilder) {
  this.form = this.formBuilder.group({
    password: ['', Validators.required],
    confirmPassword: ['', Validators.required]
  }, { validator: matchingInputsValidator('password', 'confirmPassword') });

  this.subscriptions.push(
    this.form.valueChanges.subscribe(value => {
      this.onChange(value);
      this.onTouched();
    })
  );
}
```

We also create the `validate` method to tell the parent form when the password control form is invalid or valid.

```typescript
validate(_: FormControl) {
  return this.form.valid ? null : { passwords: { valid: false, }, };
}
```

Now that we have both subforms created and defined, we can easily reuse them and compose them into other forms in our Angular application. Going back to our sign up form, we can see both subforms used as independent controls.

```html
<form [formGroup]="signupForm" (ngSubmit)="submit()">
  <app-profile-form formControlName="profile"></app-profile-form>
  <app-password-form formControlName="password"></app-password-form>
  <button>Sign Up</button>
</form>

<p>
  Form is {{signupForm.valid ? 'Valid' : 'Invalid'}}
</p>

<pre>
{{signupForm.value | json}}
</pre>
```

When we submit our form, we get the following form values.

```json
{
  "password": {
    "password": "123456",
    "confirmPassword": "123456"
  },
  "profile": {
    "firstName": "John",
    "lastName": "Doe",
    "email": "example@example.com"
  }
}
```

Angular passes back the form value the way we structured our subforms making it easy to gather multiple values from composed and nested forms. By using the `ControlValueAccessor` API we can make our forms reusable and composable for our Angular applications. Find the full working [demo here](https://stackblitz.com/edit/angular-egd6pp).