web-dev-qa-db-fra.com

Accédez à FormControl à partir du composant de formulaire personnalisé dans Angular

J'ai un composant de contrôle de formulaire personnalisé dans mon application Angular, qui implémente l'interface ControlValueAccessor.

Cependant, je souhaite accéder à l'instance FormControl associée à mon composant. J'utilise des formulaires réactifs avec FormBuilder et j'effectue un contrôle de formulaire à l'aide de l'attribut formControlName.

SO, comment puis-je accéder à FormControl instance de l'intérieur de mon composant de formulaire personnalisé?

41
Slava Fomin II

Cette solution est née de la discussion dans le répertoire Angular). Assurez-vous de la lire ou mieux de participer si vous êtes intéressé par ce problème.


J'ai étudié le code de la directive FormControlName et cela m'a inspiré pour écrire la solution suivante:

@Component({
  selector: 'my-custom-form-component',
  templateUrl: './custom-form-component.html',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: CustomFormComponent,
    multi: true
  }]
})
export class CustomFormComponent implements ControlValueAccessor, OnInit {

  @Input() formControlName: string;

  private control: AbstractControl;


  constructor (
    @Optional() @Host() @SkipSelf()
    private controlContainer: ControlContainer
  ) {
  }


  ngOnInit () {

    if (this.controlContainer) {
      if (this.formControlName) {
        this.control = this.controlContainer.control.get(this.formControlName);
      } else {
        console.warn('Missing FormControlName directive from Host element of the component');
      }
    } else {
      console.warn('Can\'t find parent FormGroup directive');
    }

  }

}

J'injecte le parent FormGroup au composant, puis j'obtiens le FormControl spécifique en utilisant le nom du contrôle obtenu via la liaison formControlName.

Cependant, sachez que cette solution est spécialement conçue pour le cas d'utilisation où la directive FormControlName est utilisée sur l'élément Host. Cela ne fonctionnera pas dans d'autres cas. Pour cela, vous devrez ajouter une logique supplémentaire. Si vous pensez que cela devrait être traité par Angular, assurez-vous de visiter la discussion .

43
Slava Fomin II

L'utilisation de formControlName comme paramètre d'entrée ne fonctionne pas lors de la liaison via le [formControl] directive.

Voici une solution qui fonctionne dans les deux sens sans aucun paramètre d'entrée.

export class MyComponent implements AfterViewInit {

  private control: FormControl;

  constructor(
    private injector: Injector,
  ) { }

  // The form control is only set after initialization
  ngAfterViewInit(): void {
    const ngControl: NgControl = this.injector.get(NgControl, null);
    if (ngControl) {
      this.control = ngControl.control as FormControl;
    } else {
      // Component is missing form control binding
    }
  }
}
27
Randy

Comme @Ritesh a déjà écrit dans le commentaire, vous pouvez passer le contrôle de formulaire en tant que liaison d'entrée:

<my-custom-form-component [control]="myForm.get('myField')" formControlName="myField">
</my-custom-form-component>

Et ensuite, vous pouvez obtenir une instance de contrôle de formulaire dans votre composant de formulaire personnalisé comme suit:

@Input() control: FormControl;
3
Yuri Beliakov

Pour tous ceux qui viennent ici en 2019, avec Angular 6/7, la solution qui ne déclenche pas d'avertissement de dépréciation est celle décrite dans cette réponse:

https://stackoverflow.com/a/56061527/13412

Pour plus de détails, regardez cette présentation , comme décrit ci-dessus.

2
AsGoodAsItGets