Angular provides a powerful way to create custom form controls to enhance the functionality and reusability of your application. In this article, we'll walk through the process of creating a custom form control step by step, with a detailed explanation, background on NG_VALUE_ACCESSOR
, and a practical example.
Background on NG_VALUE_ACCESSOR
In Angular, NG_VALUE_ACCESSOR
is a special injection token used to register and provide a way for Angular forms to communicate with custom form controls. It's a crucial part of creating custom form controls because it allows Angular to integrate them seamlessly into the reactive forms framework.
When you define a custom form control that implements the ControlValueAccessor
interface and provide it using NG_VALUE_ACCESSOR
, you're essentially telling Angular how to interact with your custom control. This includes syncing values, handling changes, and setting up two-way data binding.
ControlValueAccessor Methods
The ControlValueAccessor
interface defines several methods that you must implement in your custom form control class. These methods enable the interaction between your custom control and Angular forms:
interface ControlValueAccessor<T> {
writeValue(obj: T): void;
registerOnChange(fn: (value: T) => void): void;
registerOnTouched(fn: () => void): void;
setDisabledState?(isDisabled: boolean): void;
}
writeValue(value: any)
: This method is used to write a value from the model into the view. It's called when you programmatically set the value of your custom form control. Inside this method, you typically update the internal state of your control.registerOnChange(fn: any)
: This method registers a callback function that Angular calls whenever the value of your custom control changes. You should store this callback and call it when your control's value changes to notify Angular.registerOnTouched(fn: any)
: This method is similar toregisterOnChange
, but it's used to register a callback function that Angular calls when the custom control is "touched" or loses focus. It's typically used to mark the control as touched and trigger validation.setDisabledState(isDisabled: boolean)
: This optional method allows you to set the disabled state of your custom control. It's useful when you want to enable or disable the control programmatically.
Now we will see how we can create a Poll form control using the concept we have learnt.
Detailed Steps to Create a Custom Poll Control
Prerequisites
Before we dive into creating custom form controls, make sure you have the following prerequisites installed:
- Node.js and npm (Node Package Manager)
- Angular CLI (Command Line Interface) - You can install it globally using
npm install -g @angular/cli
.
Step 1: Set Up the Angular Project
If you haven't already, create a new Angular project using the Angular CLI:
ng new custom-poll-control-example
Navigate to the project directory:
cd custom-poll-control-example
Step 2: Create a Custom Poll Control
Now, create a custom poll control component using the Angular CLI:
ng generate component poll-control
Step 3: Implement the Custom Poll Control with Value Accessor Methods
In the poll-control
component, open the poll-control.component.ts
file, and define the custom form control with value accessor methods:
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-poll-control',
templateUrl: './poll-control.component.html',
styleUrls: ['./poll-control.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => PollControlComponent),
multi: true,
},
],
})
export class PollControlComponent implements ControlValueAccessor, OnInit {
@Input() pollOptions: string[]; // Input property to receive poll options
selectedOptions: string[] = [];
onChange: any = () => {};
onTouched: any = () => {};
constructor() {}
ngOnInit() {}
writeValue(value: string[]) {
this.selectedOptions = value;
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean) {
// Implement if needed
}
updateSelectedOptions(option: string) {
if (this.isSelected(option)) {
this.selectedOptions = this.selectedOptions.filter((item) => item !== option);
} else {
this.selectedOptions.push(option);
}
this.onChange(this.selectedOptions);
this.onTouched();
}
isSelected(option: string) {
return this.selectedOptions.includes(option);
}
}
In this code, we implement the ControlValueAccessor
interface with methods like writeValue
, registerOnChange
, and registerOnTouched
. We also create a method updateSelectedOptions
to handle checkbox changes and update the form control value.
Step 4: Create the Custom Poll Control Template
In the poll-control
component directory, open the poll-control.component.html
file, and create the HTML template for the poll control:
<div>
<div *ngFor="let option of pollOptions">
<label>
<input
type="checkbox"
[checked]="isSelected(option)"
(change)="updateSelectedOptions(option)"
/>
{{ option }}
</label>
</div>
</div>
Step 5: Using the Custom Poll Control
In a parent component (e.g., app.component.html
), use the custom poll control to create and display a poll:
<form [formGroup]="pollForm">
<app-poll-control [pollOptions]="options" formControlName="pollOptions"></app-poll-control>
<button (click)="submitPoll()">Submit Poll</button>
</form>
Step 6: Handling the Poll Data
In your parent component (e.g., app.component.ts
), define a FormGroup for the poll form, handle the submitted data, and set up the form control:
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
options: string[] = ['BreakFast', 'Lunch', 'Dinner'];
pollForm: FormGroup;
constructor(private fb: FormBuilder) {
this.pollForm = this.fb.group({
pollOptions: [[]], // Initialize with an empty array
});
}
submitPoll() {
const selectedOptions = this.pollForm.value.pollOptions;
console.log('Selected Poll Options:', selectedOptions);
}
}
Output
Conclusion
In this example, we created a custom poll control in Angular using the ControlValueAccessor
interface. Users can select multiple options, and the parent component can handle the selected options. This demonstrates how you can create more complex custom form controls in Angular to suit your application's requirements. You can further enhance this example by adding features like dynamic poll creation and result display.
Thank's for your time, see you soon :)
Top comments (0)