How to implement ControlValueAccessor in Angular

Introduction

In this article, I will explain about how to implement control value accessor in Angular. Control Value Accessor is an interface that provides us the power to leverage the Angular forms API and create a communication between Angular Form API and the DOM element. It provides us many facilities in angular like we can create custom controls or custom component with the help of control value accessor interface.

Prerequisites

  • Angular 12
  • HTML/Bootstrap

For this article, I have created an Angular project using Angular 12. For creating an Angular project, we need to follow the following steps:

Create Project

I have created a project using the following command in the Command Prompt.

ng new controlValueAccessorExample

Open a project in Visual Studio Code using the following commands.

cd controlValueAccessorExample
Code .

Now in Visual Studio your project looks like as below.

 Let's create Custom Component using the following command:

ng g c Custom

So now 4 files will automatically created in your project like as below

So first of all you need to implement ControlValueAccessor interface in custom component. After implementation you will have three methods in component.ts file as below:

import { Component, OnInit } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';

@Component({
  selector: 'app-custom',
  templateUrl: './custom.component.html',
  styleUrls: ['./custom.component.css']
})
export class CustomComponent implements ControlValueAccessor {

  constructor() { }
  
  onChange: any = () => {}
  onTouch: any = () => {}

  set value(val: string){}  

  writeValue(obj: any): void {
    throw new Error('Method not implemented.');
  }
  registerOnChange(fn: any): void {
    throw new Error('Method not implemented.');
  }
  registerOnTouched(fn: any): void {
    throw new Error('Method not implemented.');
  }

}

So first all of you need to understand these methods what functionality they will provide:

  • onChange - the callback function to register on UI change
  • onTouch - the callback function to register on element touch
  • set value(val: any) - sets the value used by the ngModel of the element
  • writeValue(obj: any) - This will write the value to the view if the value changes occur on the model programmatically
  • registerOnChange(fn: any) - When the value in the UI is changed, this method will invoke a callback function
  • registerOnTouch(fn: any) - When the element is touched, this method will get called

Now we can use ControlValueAccessor like as below code:

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

@Component({
  selector: 'app-custom',
  templateUrl: './custom.component.html',
  styleUrls: ['./custom.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: CustomComponent,
      multi: true
    }]
})

export class CustomComponent implements ControlValueAccessor {
  field= "";

  constructor() { }

  onChange: any = () => {}
  onTouch: any = () => {}

  // sets the value used by the ngModel of the element
  set value(val: string){
      this.field = val
      this.onChange(val)
      this.onTouch(val)
  }

  // This will will write the value to the view if the the value changes occur on the model programmatically
  writeValue(value: any){
    this.value = value
  }

  // When the value in the UI is changed, this method will invoke a callback function
  registerOnChange(fn: any){
    this.onChange = fn
  }

  // When the element is touched, this method will get called
  registerOnTouched(onTouched: Function) {
    this.onTouch = onTouched;
  }
}

Custom.Component.html

<input [(ngModel)]="value"/>
<p>Internal data field:{{field}}</p>

App.componet.html

<app-custom  [(ngModel)]="data"></app-custom>
<p>Data here:{{data}}</p>

App.componet.ts

import { Component, ViewChild } from '@angular/core';
import { CustomComponent } from './custom/custom.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  data:string='';
}

Let's run the project using following command:

ng serve

Summary

In this article, I have discussed about implementation of control value accessor in Angular.