Angular4 - No value accessor for form control

2019-01-07 09:58发布

问题:

I have a little prob with my form.

I did a custom element :

<div formControlName="surveyType">
  <div *ngFor="let type of surveyTypes"
       (click)="onSelectType(type)"
       [class.selected]="type === selectedType">
    <md-icon>{{ type.icon }}</md-icon>
    <span>{{ type.description }}</span>
  </div>
</div>

I try to add the formControlName but angular dont want to know anything and just saying :

ERROR Error: No value accessor for form control with name: 'surveyType'

I tried to add ngDefaultControl without success. It seems it s because there is no input/select... but i dont know what to do.

I would like to bind my click to this formControl in order that when someone click on the entire card that push my 'type' into the formControl. Is it possible?

回答1:

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 NgMode by Cory Rylan


回答2:

I think you should use formControlName="surveyType" on an input and not on a div