2 votes

Formulaires réactifs Angular - Permettre aux enfants imbriqués de déterminer l'activation/désactivation

J'ai un formulaire réactif imbriqué dans angular.

L'enfant a 2 propriétés et la seconde est activée ou désactivée en fonction de la valeur de la première.

Le formulaire parent possède un bouton d'édition qui permet d'activer/désactiver des champs par le biais de la fonction this.parentForm.enable() .

Mon problème est que cela active le deuxième champ enfant quoi qu'il arrive et n'utilise pas la logique de l'enfant pour déterminer s'il doit être activé ou désactivé.

Quelle est l'approche suggérée pour les formulaires réactifs avec une logique d'activation/désactivation dans les enfants ? J'ai essayé d'utiliser [disabled] mais cela n'a pas fonctionné et j'ai reçu des avertissements m'indiquant que je ne devais pas le faire.

Voici un stackblitz avec un exemple de problème.

En edit est cliqué, il ne devrait activer la dernière entrée que si Yes est vérifié. Elle doit être désactivée si No est vérifié.

4voto

bryan60 Points 4876

Ajoutez donc une fonction comme celle-ci à votre contrôleur :

 private setChildState() { 
    // this function gets the ctrl to enable/disable and does so based on the value
    const v = this.parentForm.get('typeDetails').get('identity').value;
    let ctrl = this.parentForm.get('typeDetails').get('identityname');
    if (v === 'yes') {
      ctrl.enable();
    } else {
      ctrl.disable();
    }
 }

pour définir l'état d'activation/désactivation de votre formulaire enfant, il suffit d'ajouter ces quelques lignes :

ceci dans votre ngOnViewInit()

// this listens to value changes and updates form state
this.parentForm.get('typeDetails').get('identity').valueChanges.subscribe(v => {
  this.setChildState();
});

et ensuite ceci dans votre fonction d'édition :

this.setChildState();

blitz fixe : https://stackblitz.com/edit/angular-bwfn35?file=src/app/app.component.ts

EDIT :

si vous voulez garder tout cela (principalement) dans l'enfant, changez votre enfant en ceci :

  ngOnInit() {
    this.identifyForm.get('identity').valueChanges.subscribe(v => {
      this.setState();
    })
  }

  setState() {
    const v = this.identifyForm.get('identity').value;
    let ctrl = this.identifyForm.get('identityname');
    if (v === 'yes') {
      ctrl.enable();
    } else {
      ctrl.disable();
    }
  }

puis ajoutez ceci à votre fonction d'édition dans le parent :

this.childComponent.setState();

0voto

Vamsi Ambati Points 211

Déplacez le code du groupe radio vers votre composant parent et souscrivez aux changements.

sur la base de la valeur ou pas de

activer et désactiver le contrôle de formulaire du composant enfant

classé stackblitz : https://stackblitz.com/edit/angular-kszjwj

0voto

Eliseo Points 4154

Une autre approche consiste à améliorer la directive "enabled" de ce système. réponse de stackoverflow

Nous allons améliorer la directive pour permettre de désactiver non seulement le contrôle mais aussi tous les contrôles d'un formulaire.

@Directive({
  selector: '[disableControl]'
})
export class DisableControlDirective {
  @Input() set disableControl(condition: boolean) {
    if (this.ngControl) { //if is an ngControl
      if (condition)
        this.ngControl.control.disable();
      else
        this.ngControl.control.enable();
    }
    if (this.controls) { //if is a formGroup, we ask about the inners controls
      this.controls.forEach((x: any) => {
        let control:boolean=false;
        if (this.innerControl) //we check if the control has
                               //his own DisableControlDirective
          control=(this.innerControl.find(inner=>x==inner.ngControl)!=null)

        if (!control) { //if it has not a own DisabledControlDirective
          if (condition)
            x.control.disable();
          else
            x.control.enable()
        }
      })
    }
  }
  @ContentChildren(NgControl) controls: QueryList<NgControl>
  @ContentChildren(DisableControlDirective)
             innerControl:QueryList<DisableControlDirective>
  //see that make public ngControl to use when check if a innerControl has 
  //the directive
  constructor(@Optional() public ngControl: NgControl) {}
}

Si nous appliquons la directive à un fromGroup, tous les contrôles inners sont désactivés/activés. Pour obtenir le contrôle interne, nous utilisons @ContentChildren(NgControl) . Lorsque nous injectons le NgControl, nous devons mettre @Optional() parce que dans un FormGroup nous n'avons PAS de NgControl - rappelez-vous que NgControl est tout ce qui a la directive [formControlName], [NgModel] ou [formControl].

Nous devons vérifier si nos contrôles internes n'ont pas de directive [disableControl]. Dans ce cas, nous devons sauter ce contrôle. Pour cela, nous devons récupérer ces contrôles en utilisant @ContentChildren(DisableControlDirective) et le vérifier.

Notre forme devient très "facile", mais nous passons comme @Input le mode d'édition à l'enfant

<form [formGroup]="parentForm" [disableControl]="!editMode" (ngSubmit)="onSave()">
  <input formControlName="id">
  <input formControlName="name">
  <app-child-component [editMode]="editMode"></app-child-component>
</form>

//and our children component

<form [formGroup]="identifyForm" [disableControl]="!editMode">
  <input type="radio" name="identity" value="yes" formControlName="identity"> Yes
  <input type="radio" name="identity" value="no" formControlName="identity" > No

  <input formControlName="identityname" 
     [disableControl]="!editMode || identifyForm.get('identity').value=='no'">
</form>

Nous pouvons voir le résultat final dans ce stackblitz

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X