web-dev-qa-db-fra.com

Angular4 - Pas d'accesseur de valeur pour le contrôle de formulaire

J'ai un élément personnalisé:

<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>

Lorsque j'essaie d'ajouter le formControlName, un message d'erreur apparaît:

ERROR Error: Aucun accesseur de valeur pour le contrôle de formulaire portant le nom: 'surveyType'

J'ai essayé d'ajouter ngDefaultControl sans succès. Il semble que c'est parce qu'il n'y a pas d'entrée/sélection ... et je ne sais pas quoi faire.

Je voudrais lier mon clic à ce formulaireContrôle afin que lorsque quelqu'un clique sur toute la carte, cela insère mon "type" dans le formulaireContrôle. C'est possible?

109
jbtd

Vous ne pouvez utiliser formControlName que sur les directives qui implémentent ControlValueAccessor .

Implémenter l'interface

Donc, pour faire ce que vous voulez, vous devez créer un composant qui implémente ControlValueAccessor , ce qui signifie implémentant les trois fonctions suivantes :

  • writeValue (indique Angular comment écrire la valeur du modèle dans la vue)
  • registerOnChange (enregistre une fonction de gestionnaire appelée lorsque la vue change)
  • registerOnTouched (enregistre un gestionnaire à appeler lorsque le composant reçoit un événement tactile, utile pour savoir si le composant a été mis au point).

Enregistrer un fournisseur

Ensuite, vous devez dire à Angular que cette directive est un ControlValueAccessor (l'interface ne sera pas coupée car elle est extraite du code lorsque TypeScript est compilé en JavaScript). Pour ce faire, vous devez enregistrer un fournisseur .

Le fournisseur doit indiquer NG_VALUE_ACCESSOR et tiliser une valeur existante . Vous aurez également besoin d'un forwardRef ici. Notez que _NG_VALUE_ACCESSOR_ devrait être un fournisseur multiple .

Par exemple, si votre directive personnalisée s'appelle MyControlComponent, vous devez ajouter quelque chose le long des lignes suivantes à l'intérieur de l'objet transmis au décorateur _@Component_:

_providers: [
  { 
    provide: NG_VALUE_ACCESSOR,
    multi: true,
    useExisting: forwardRef(() => MyControlComponent),
  }
]
_

Usage

Votre composant est prêt à être utilisé. Avec formulaires basés sur des modèles , la liaison ngModel fonctionnera désormais correctement.

Avec formulaires réactifs , vous pouvez maintenant utiliser correctement formControlName et le contrôle de formulaire se comportera comme prévu.

Ressources

191
Lazar Ljubenović

Je pense que vous devriez utiliser formControlName="surveyType" sur un input et non sur un div

48
Vega