You can use formControlName only on directives which implement ControlValueAccessor.
Implement the interface
So, in order to do what you want, you have to create a component which implements ControlValueAccessor, which means implementing the following three functions:
writeValue(tells Angular how to write value from model into view)registerOnChange(registers a handler function that is called when the view changes)registerOnTouched(registers a handler to be called when the component receives a touch event, useful for knowing if the component has been focused).
Register a provider
Then, you have to tell Angular that this directive is a ControlValueAccessor (interface is not gonna cut it since it is stripped from the code when TypeScript is compiled to JavaScript). You do this by registering a provider.
The provider should provide NG_VALUE_ACCESSOR and use an existing value. You’ll also need a forwardRef here. Note that NG_VALUE_ACCESSOR should be a multi provider.
For example, if your custom directive is named MyControlComponent, you should add something along the following lines inside the object passed to @Component decorator:
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => MyControlComponent),
}
]
Usage
Your component is ready to be used. With template-driven forms, ngModel binding will now work properly.
With reactive forms, you can now properly use formControlName and the form control will behave as expected.
Resources
- Custom Form Controls in Angular by Thoughtram
- Angular Custom Form Controls with Reactive Forms and NgModel by Cory Rylan