iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
NG_VALUE_ACCESSOR is the Angular dependency-injection token that lets Angular Forms find a ControlValueAccessor for a control. The accessor is the bridge between the form model and your component’s UI: writeValue carries model changes into the view, while the callback saved by registerOnChange carries user edits back to the model.
How the ControlValueAccessor bridge works
Angular’s ControlValueAccessor API defines an interface between Angular Forms and a control’s view. A form directive such as formControl, formControlName, or ngModel uses a registered accessor to coordinate values and control state.
There are two distinct value directions. When the form model changes, Angular calls writeValue so the component can update its display. When a user changes the component, the component calls the callback Angular supplied through registerOnChange. Do not call that callback from writeValue: doing so can make a model-to-view update look like a new user edit.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
| Direction | What happens | Accessor responsibility |
|---|---|---|
| Model to view | Angular Forms provides a value to the control. | Update the component’s displayed or internal UI state in writeValue. |
| View to model | The user changes the control. | Call the saved callback from registerOnChange with the new value. |
What the four accessor methods do
The interface has three required methods and an optional disabled-state method. Implement them according to their separate responsibilities:
#1 Best Overall
writeValue(value)receives a model value and updates the view. It is not a user-change notification.registerOnChange(fn)gives the component a callback to save. Call it when an interaction changes the control’s value.registerOnTouched(fn)gives the component a callback to save. Call it when the control is blurred or otherwise should be considered touched.setDisabledState(isDisabled), when implemented, reflects the form’s disabled state in the actual interactive UI, for example by disabling the relevant input or button.
Touched and disabled are not value changes. A control should report touch at the appropriate interaction boundary, and disabling it should prevent interaction rather than merely change its appearance.
Register a custom ControlValueAccessor with NG_VALUE_ACCESSOR
For a typical custom component, provide the component instance under NG_VALUE_ACCESSOR. Use useExisting so Angular reuses the component instance rather than constructing a second accessor, and multi: true so the provider joins the accessor providers Angular Forms can select from.
Rank #2
import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-rating-control',
template: `
<button
type="button"
[disabled]="disabled"
(click)="setRating(rating + 1)"
(blur)="markTouched()">
{{ rating }}
</button>
`,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RatingControlComponent),
multi: true
}]
})
export class RatingControlComponent implements ControlValueAccessor {
rating = 0;
disabled = false;
private onChange: (value: number) => void = () => {};
private onTouched: () => void = () => {};
writeValue(value: number | null): void {
this.rating = value ?? 0;
}
registerOnChange(fn: (value: number) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
setRating(value: number): void {
if (this.disabled) return;
this.rating = value;
this.onChange(value);
}
markTouched(): void {
this.onTouched();
}
}
This example illustrates the wiring, not a complete rating component. Adapt the value type, interaction, and display to your control. The key distinction is that writeValue updates the view without emitting a user edit, while an interaction updates the component and calls onChange.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →When ngDefaultControl is enough
A custom element that behaves like an ordinary text input and does not need special value processing may use ngDefaultControl instead of implementing a custom accessor. Angular’s DefaultValueAccessor API documents this option alongside its use for standard text inputs and textareas.
Rank #3
Use a custom ControlValueAccessor when the widget has its own value representation or interaction—for example, a rating button, composite date picker, or toggle whose UI is not simply a text-like input. For native or select controls, Angular provides specialized accessors; the SelectControlValueAccessor API includes compareWith for customizing how option values represented by objects are compared.
Diagnose “no value accessor” errors
If Angular reports that no value accessor is available for a form control, check the registration and the control’s context:
Rank #4
- Confirm the component implements
ControlValueAccessorand provides itself throughNG_VALUE_ACCESSORwithuseExistingandmulti: true. - Check that the control is used with the expected form directive and that the relevant Angular Forms package is imported for the application’s setup.
- If the element is a simple text-like custom element, consider whether
ngDefaultControlfits its behavior. If it has custom value semantics or interactions, implement and register an accessor instead.
Angular’s Forms guide describes reactive and template-driven forms and shows the propagation path: user input reaches a FormControl through the accessor, while programmatic model changes return to the view through it.
Angular Material: a specific NgControl cycle
A custom Angular Material form-field control may inject its own NgControl. In that particular arrangement, also registering the component through NG_VALUE_ACCESSOR can create a cyclic dependency. The Angular Material v9 custom form-field guide documents a different pattern: when the control exists, assign the accessor directly with ngControl.valueAccessor = this rather than adding the provider.
This is guidance for that architecture in the v9 documentation, not a universal replacement for the standard provider pattern. Check the guide and behavior for the Angular Material version used by your application before applying the workaround.
Signal Forms use a separate custom-control route
For teams adopting Angular Signal Forms, the migration guide describes custom controls using FormValueControl and FormCheckboxControl. It explicitly says not to implement those interfaces together with ControlValueAccessor on the same component. Treat Signal Forms’ custom-control interfaces as a separate integration model rather than an additional accessor provider; see the Signal Forms migration guide.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →

