Angular ControlValueAccessor - ngModel with Child Component
May 17, 2023
The ControlValueAccessor
is an interface that acts as a bridge between the Angular forms API and a native element in the DOM. We can create custom form control directive by implementing the ControlValueAccessor
interface.
The
ControlValueAccessor
has following method declarations.
writeValue(obj: any): void : Writes a new value to the element.
registerOnChange(fn: any): void : Registers a callback function that is called when the control's value changes in the UI.
registerOnTouched(fn: any): void : Registers a callback function that is called by the forms API on initialization to update the form model on blur.
setDisabledState(isDisabled: boolean)?: void : Function that is called by the forms API when the control status changes to or from 'DISABLED'.
On this page we will use
ControlValueAccessor
to bind ngModel
with child component.
Complete Example
In our example we are creating parent and child component. The child component is implementing theControlValueAccessor
interface. Using its writeValue
method, we are enabling child component to bind ngModel
in parent component.
app.component.ts
import { Component } from "@angular/core"; import { Student } from "./student"; @Component({ selector: 'app-root', template: ` <app-student [ngModel]="students"></app-student> ` }) export class AppComponent { students: Student[] = [ { name: 'Mohit', age: 25 }, { name: 'Krishn', age: 30 } ]; }
import { Component, forwardRef, Renderer2, ElementRef, Provider } from "@angular/core"; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms"; import { Student } from "./student"; const CUSTOM_VALUE_ACCESSOR: Provider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StudentCVAccessorComponent), multi: true } @Component({ selector: 'app-student', template: ` <div *ngFor="let std of students"> <p>{{std.name}} - {{std.age}}</p> </div> `, providers: [CUSTOM_VALUE_ACCESSOR] }) export class StudentCVAccessorComponent implements ControlValueAccessor { students: Student[] = []; writeValue(obj: any) { this.students = obj; } registerOnChange(fn: any) { } registerOnTouched(fn: any) { } setDisabledState(isDisabled: boolean) { } }
export interface Student { name?: String; age?: number; }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { StudentCVAccessorComponent } from './student-cvaccessor.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent, StudentCVAccessorComponent ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
