Understanding Angular's Control Value Accessor Interface
Tags: angular, reactiveprogramming, javascript
Published: 2019-07-02 23:52:19

---
title: Understanding Angular's Control Value Accessor Interface
published: true
description: How to use Angular's Control Value Accessor Interface to conquer all Angular form problems. 
tags: Angular, Reactive Programming, JavaScript
---


If you're dealing with forms in Angular on a regular basis, one of the most powerful things you can learn is how to use the Control Value Accessor interface. The CVA interface is a bridge between FormControls and their elements in the DOM. A component extending the CVA interface can create a custom form control that behaves the same as a regular input or radio button. 

## Why Would You Want to Use the Control Value Accessor Interface?

Sometimes you may need to create a custom form element that you want to be able to use as a regular FormControl. (For a better understanding of FormControls and other Angular Form classes you might want to read my article <a href="https://dev.to/angular/managing-nested-and-dynamic-forms-in-angular-1he6">here</a>) For example, creating a 5 star rating UI that updates a single value. We'll use this example in our demo. 

<img src="https://thepracticaldev.s3.amazonaws.com/i/u7nuzhlku5y7k4mwtsfn.gif" alt="star rating input">

There's a lot happening in the UI here - stars changing colors as they're hovered over and displaying different text for each ratings, but all we care about is saving a number value 0-5. 

## Implementing the CVA

To use the CVA interface in a component, you must implement its three required methods: `writeValue`, `registerOnChange`, and `registerOnTouched`. There is also an optional method `setDisabledState`. 

The `writeValue` method is called in 2 situations:
- When the formControl is instantiated

``` typescript
rating = new FormControl({value: null, disabled: false}) 
```
- When the formControl value changes
```typescript
rating.patchValue(3)
```

The `registerOnChange` method should be called whenever the value changes - in our case, when a star is clicked on. 

The `registerOnTouched` method should be called whenever our UI is interacted with - like a blur event. You may be familiar with implementing Typeaheads from a library like Bootstrap or NGX-Bootstrap that has an `onBlur` method. 

The `setDisabledState` method is called in 2 situations:

- When the formControl is instantiated with a disabled prop

``` typescript
rating = new FormControl({value: null, disabled: false}) 
```
- When the formControl disabled status changes
```typescript
rating.disable();
rating.enable();
```

A star rating component implementing the CVA may look something like this:

```typescript
export class StarRaterComponent implements ControlValueAccessor {
  public ratings = [
    {
      stars: 1,
      text: 'must GTFO ASAP'
    },
    {
      stars: 2,
      text: 'meh'
    },
    {
      stars: 3,
      text: 'it\'s ok'
    },
    {
      stars: 4,
      text: 'I\'d be sad if a black hole ate it'
    },
    {
      stars: 5,
      text: '10/10 would write review on Amazon'
    }
  ]
  public disabled: boolean;
  public ratingText: string;
  public _value: number;

  onChanged: any = () => {}
  onTouched: any = () => {}

  writeValue(val) {
    this._value = val;
  }

  registerOnChange(fn: any){
    this.onChanged = fn
  }
  registerOnTouched(fn: any){
    this.onTouched = fn
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  setRating(star: any) {
    if(!this.disabled) {
      this._value = star.stars;
      this.ratingText = star.text
      this.onChanged(star.stars);
      this.onTouched();
    }
  }

}
```

You must also tell Angular that your component implementing the CVA is a value accessor(remember, interfaces aren't compiled in TypeScript) using NG_VALUE_ACCESSOR and forwardRef. 

```typescript
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'gr-star-rater',
  templateUrl: './star-rater.component.html',
  styleUrls: ['./star-rater.component.less'],
  providers: [     
    {
      provide: NG_VALUE_ACCESSOR, 
      useExisting: forwardRef(() => StarRaterComponent),
      multi: true     
    }   
  ]
})
export class StarRaterComponent implements ControlValueAccessor {
...
```

## Using Your New CVA Component

Now, to use your fancy new CVA component, you can treat is as a plain old FormControl. 

```typescript 
this.galaxyForm = new FormGroup({
  rating: new FormControl({value: null, disabled: true})
});
```

```html
<form [formGroup]="galaxyForm" (ngSubmit)="onSubmit()">
  <h1>Galaxy Rating App</h1>
  <div class="form-group">
    <label>
      Rating:
      <gr-star-rater formControlName="rating"></gr-star-rater>
    </label>
  </div>
  <div class="form-group">
    <button type="submit">Submit</button>
  </div>
</form>
```

Tada! Not so scary, huh? Questions or need help with Angular Reactive Forms? Let me know!