Mastering Angular Control Value Accessor: A Guide for Angular Developer

chintanonweb - Aug 25 '23 - - Dev Community

Introduction

As an Angular expert and developer in the IT industry, I have encountered various scenarios where custom form controls were required to enhance user experience and collect data efficiently. One powerful tool that Angular offers in this regard is the “Control Value Accessor.” This feature might sound intimidating at first, but fear not! In this blog post, we will demystify the Angular Control Value Accessor and explore how it empowers developers to create seamless custom form controls.

Understanding Control Value Accessor

In Angular, forms play a critical role in handling user input and validating data. Reactive forms, a feature introduced in Angular, provide a more declarative approach to building forms compared to template-driven forms. When it comes to custom form controls, Angular introduces the Control Value Accessor interface as a bridge between form controls and native form elements. The Control Value Accessor serves as a two-way communication channel, enabling custom form controls to interact seamlessly with Angular forms.

The Role of Control Value Accessor

The primary purpose of the Control Value Accessor is to provide a consistent way to work with form controls, abstracting the underlying native form elements. By implementing this interface, custom form controls can easily integrate with Angular’s reactive forms API, making them more accessible, reusable, and easier to maintain.

Implementing Control Value Accessor

Let’s delve into the steps required to implement a custom form control using Control Value Accessor:

Step 1: Create the Custom Control Component

Start by generating a new Angular component that will represent your custom form control. This component will need to implement the ControlValueAccessor interface, which requires implementing four essential methods: writeValue, registerOnChange, registerOnTouched, and setDisabledState.

Step 2: Connect the Custom Control to Angular Forms

To enable seamless integration with Angular forms, you need to register the custom control with Angular’s dependency injection using the NG_VALUE_ACCESSOR token. This step ensures that Angular knows how to connect the custom control to form elements and form control instances.

Step 3: Handle Value Changes and User Interactions

In the writeValue method, you update the custom control’s internal state with the value received from the form control. The registerOnChange method is where you notify the form control of any changes in the custom control’s value. Similarly, the registerOnTouched method is used to inform Angular when the custom control has been touched (i.e., when a user interacts with it). Lastly, the setDisabledState method allows you to enable or disable the custom control programmatically.

Creating a Practical Example: A Custom Slider Control

Let’s walk through a practical example of creating a custom slider control using Control Value Accessor. In this example, we’ll build a slider input that allows users to select a value between a defined minimum and maximum range.

Step 1: Creating the Component

Create a new component called slider-control to represent the custom slider control. Implement the ControlValueAccessor interface and define the necessary methods: writeValue, registerOnChange, registerOnTouched, and setDisabledState.

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

@Component({
  selector: 'app-slider-control',
  templateUrl: './slider-control.component.html',
  styleUrls: ['./slider-control.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => SliderControlComponent),
      multi: true
    }
  ]
})
export class SliderControlComponent implements ControlValueAccessor {
  @Input() min: number = 0;
  @Input() max: number = 100;
  value: number = 0;
  disabled: boolean = false;

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

  writeValue(value: number): void {
    this.value = value;
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }

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

  updateValue(event: Event): void {
    const newValue = (event.target as HTMLInputElement).valueAsNumber;
    this.value = newValue;
    this.onChange(newValue);
    this.onTouch();
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Building the Template

Design the template for the custom slider control using an HTML input element of type “range.” Implement the necessary bindings to handle user interactions and update the control’s value.

<input
  type="range"
  [min]="min"
  [max]="max"
  [value]="value"
  [disabled]="disabled"
  (input)="updateValue($event)"
/>
Enter fullscreen mode Exit fullscreen mode

Step 3: Using the Custom Slider Control

In the parent component, import the slider-control component, and include it in the parent template. Bind the custom control to a reactive form control to manage its value.

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

@Component({
  selector: 'app-root',
  template: `
    <form [formGroup]="form">
      <app-slider-control formControlName="slider"></app-slider-control>
    </form>

    <div>Slider value: {{ form.get('slider')?.value }}</div>
  `
})
export class AppComponent {
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      slider: [50] // Default value for the slider control
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Mastering the Angular Control Value Accessor opens up a world of possibilities for creating powerful and user-friendly custom form controls. By understanding how this interface acts as a bridge between your custom controls and Angular’s reactive forms, you can create dynamic and reusable components with ease. Embrace the Control Value Accessor, and elevate your Angular development skills to build better and more intuitive user experiences. Happy coding!

Note: The example provided in this blog post is for educational purposes only. You are encouraged to adapt and modify the code as needed to fit your specific use case.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .