Comment puis-je créer un composant personnalisé qui fonctionnerait comme une <input>
balise native ? Je veux que mon contrôle de formulaire personnalisé puisse prendre en charge ngControl, ngForm, [(ngModel)].
Si je comprends bien, je dois implémenter certaines interfaces pour que mon propre contrôle de formulaire fonctionne comme un contrôle natif.
De plus, il semble que la directive ngForm ne se lie que pour les <input>
balises, est-ce exact ? Comment puis-je gérer cela?
Laissez-moi vous expliquer pourquoi j'ai besoin de cela. Je veux envelopper plusieurs éléments d'entrée pour les rendre capables de fonctionner ensemble comme une seule entrée. Y a-t-il une autre façon de gérer cela? Encore une fois: je veux rendre ce contrôle comme le contrôle natif. Validation, ngForm, liaison bidirectionnelle ngModel et autres.
ps: J'utilise Typescript.
la source
Réponses:
En fait, il y a deux choses à mettre en œuvre:
ngModel
lui-mêmeControlValueAccessor
qui implémentera le pont entre ce composant etngModel
/ngControl
Prenons un échantillon. Je souhaite implémenter un composant qui gère une liste de balises pour une entreprise. Le composant permettra d'ajouter et de supprimer des balises. Je souhaite ajouter une validation pour m'assurer que la liste des balises n'est pas vide. Je vais le définir dans mon composant comme décrit ci-dessous:
Le
TagsComponent
composant définit la logique pour ajouter et supprimer des éléments dans latags
liste.Comme vous pouvez le voir, il n'y a pas d'entrée dans ce composant mais un
setValue
seul (le nom n'est pas important ici). Nous l'utilisons plus tard pour fournir la valeur dungModel
au composant. Ce composant définit un événement pour notifier lorsque l'état du composant (la liste des balises) est mis à jour.Implémentons maintenant le lien entre ce composant et
ngModel
/ngControl
. Cela correspond à une directive qui implémente l'ControlValueAccessor
interface. Un fournisseur doit être défini pour cet accesseur de valeur par rapport auNG_VALUE_ACCESSOR
jeton (n'oubliez pas de l'utiliserforwardRef
car la directive est définie après).La directive attachera un écouteur d'événement sur l'
tagsChange
événement de l'hôte (c'est-à-dire le composant auquel la directive est attachée, c'est-à-dire leTagsComponent
). LaonChange
méthode sera appelée lorsque l'événement se produira. Cette méthode correspond à celle enregistrée par Angular2. De cette façon, il sera informé des modifications et met à jour en conséquence le contrôle de formulaire associé.Le
writeValue
est appelé lorsque la valeur liée dans lengForm
est mise à jour. Après avoir injecté le composant attaché (ie TagsComponent), nous pourrons l'appeler pour passer cette valeur (voir lasetValue
méthode précédente ).N'oubliez pas de fournir le
CUSTOM_VALUE_ACCESSOR
dans les liaisons de la directive.Voici le code complet de la custom
ControlValueAccessor
:De cette façon, lorsque je supprime tous les éléments
tags
de l'entreprise, l'valid
attribut ducompanyForm.controls.tags
contrôle devientfalse
automatiquement.Consultez cet article (section "Composant compatible NgModel") pour plus de détails:
la source
<textfield>
,<dropdown>
? Est-ce une manière «angulaire»?Je ne comprends pas pourquoi chaque exemple que je trouve sur Internet doit être si compliqué. Pour expliquer un nouveau concept, je pense qu'il est toujours préférable d'avoir l'exemple le plus simple et fonctionnel possible. Je l'ai distillé un peu:
HTML pour formulaire externe utilisant le composant implémentant ngModel:
Composant autonome (pas de classe `` accesseur '' séparée - peut-être que je manque le point):
En fait, je viens de résumer tout cela dans une classe abstraite que j'étends maintenant avec chaque composant dont j'ai besoin pour utiliser ngModel. Pour moi, c'est une tonne de codes généraux et standard dont je peux me passer.
Edit: Le voici:
Voici un composant qui l'utilise: (TS):
HTML:
la source
@angular/forms
importations de mise à jour juste:import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
CORE_DIRECTIVES
et de les ajouter dans le@Component
car ils sont fournis par défaut maintenant depuis Angular2 final. Cependant, selon mon IDE, "les constructeurs pour les classes dérivées doivent contenir un" super "appel.", Donc j'ai dû ajoutersuper();
au constructeur de mon composant.Il y a un exemple dans ce lien pour la version RC5: http://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel
Nous sommes alors en mesure d'utiliser ce contrôle personnalisé comme suit:
la source
L'exemple de Thierry est utile. Voici les importations nécessaires à l'exécution de TagsValueAccessor ...
la source
J'ai écrit une bibliothèque qui permet de réduire un peu passe- partout pour ce cas:
s-ng-utils
. Certaines des autres réponses donnent un exemple d'encapsulation d'un contrôle de formulaire unique . L' utilisations-ng-utils
qui peut être fait très simplement à l' aideWrappedFormControlSuperclass
:Dans votre message, vous mentionnez que vous souhaitez intégrer plusieurs contrôles de formulaire dans un seul composant. Voici un exemple complet faisant cela avec
FormControlSuperclass
.Vous pouvez ensuite utiliser
<app-location>
avec[(ngModel)]
,[formControl]
, validateurs sur mesure - tout ce que vous pouvez faire avec les contrôles supports angulaires de la boîte.la source
Vous pouvez également résoudre ce problème avec une directive @ViewChild. Cela donne au parent un accès complet à toutes les variables membres et fonctions d'un enfant injecté.
Voir: Comment accéder aux champs d'entrée du composant de formulaire injecté
la source
Pourquoi créer un nouvel accesseur de valeur lorsque vous pouvez utiliser le ngModel interne. Chaque fois que vous créez un composant personnalisé qui contient une entrée [ngModel], nous instancions déjà un ControlValueAccessor. Et c'est l'accesseur dont nous avons besoin.
modèle:
Composant:
Utilisé comme:
la source
innerNgModel
est défini dansngAfterViewInit
C'est assez facile à faire
ControlValueAccessor
NG_VALUE_ACCESSOR
.Vous pouvez lire cet article pour créer un champ personnalisé simple Créer un composant de champ de saisie personnalisé avec angulaire
la source