web-dev-qa-db-fra.com

Angular 4 formulaires réactifs basculent la validation pour les éléments de formulaire masqués

J'ai un formulaire réactif pour lequel aucun champ n'est requis lors du chargement. Si une option est ajoutée qui ajoutera des éléments de formulaire supplémentaires dans le groupe formGroup, les nouveaux champs affichés seront tous obligatoires. Si le champ de surnom est masqué, vous devriez pouvoir envoyer le formulaire correctement. Si le pseudo est affiché, le champ pseudo est obligatoire et le bouton d'envoi est désactivé jusqu'à ce que le champ pseudo soit plein ..__ Voici un exemple de ce que je veux faire.

Ma question est, comment puis-je activer/désactiver la validation une fois que l'élément de formulaire est affiché/masqué?

App.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';

@NgModule({
  imports:      [ BrowserModule, FormsModule, ReactiveFormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

App.component.ts

import { Component, OnInit } from '@angular/core';
import { Validators, FormControl, FormGroup, FormBuilder } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  name = 'My Reactive Form';

  constructor(
    private fb: FormBuilder
  ) {}

  myForm: FormGroup;
  showNick: boolean = false;

  ngOnInit() {
    this.myForm = this.fb.group({
      'firstName': new FormControl(),
      'nickName': new FormControl('', Validators.required),
      'lastName': new FormControl()
    })
  }

  toggleNick() {
    this.showNick = !this.showNick;
  }
}

app.component.html

<form [formGroup]="myForm">
  <div class="my-box">
    <label>
      First Name
      <input type="text" formControlName="firstName">
    </label>
  </div>
  <div class="my-box nickname">
    Nickname? &nbsp; <a (click)="toggleNick()">yes / no</a>
  </div>
  <div class="my-box" *ngIf="showNick">
    <label>
      Nickname
      <input type="text" formControlName="nickName">
      <span class="validation-message" *ngIf="!myForm.controls['nickName'].valid && myForm.controls['nickName'].dirty">
    This field is invalid
  </span>
    </label>
  </div>
  <div class="my-box">
    <label>
      Last Name
      <input type="text" formControlName="lastName">
    </label>
  </div>
  <button [disabled]="myForm.invalid">Submit</button>
</form>
3
iChido

Dans ma demande, j'ai une exigence similaire. Si l'utilisateur demande à être averti par SMS, le téléphone est requis. Sinon, le numéro de téléphone est facultatif.

J'ai écrit cette méthode:

setNotification(notifyVia: string): void {
    const phoneControl = this.customerForm.get('phone');
    if (notifyVia === 'text') {
        phoneControl.setValidators(Validators.required);
    } else {
        phoneControl.clearValidators();
    }
    phoneControl.updateValueAndValidity();
}

Il est appelé à partir de ce code qui se trouve dans le ngOnInit:

    this.customerForm.get('notification').valueChanges
                     .subscribe(value => this.setNotification(value));

Si l'utilisateur modifie le champ de notification (qui est un bouton radio), il appelle la méthode setNotification en transmettant la valeur. Si la valeur est notification par 'texte', la validation du téléphone est définie sur Requise.

Sinon, la validation du champ de téléphone est effacée.

Ensuite, il doit appeler updateValueAndValidity pour mettre à jour les informations du formulaire avec cette nouvelle validation.

10
DeborahK

Même les champs sont cachés de l'utilisateur, les champs sont actifs dans le réactif. Donc, vous devez simplement désactiver le champ de réactif en utilisant le code suivant

this.myForm.get("nickName").disable();

Changer la fonction toggleNick () comme indiqué ci-dessous

toggleNick() {
    this.showNick = !this.showNick;
    if(showNick) {
         this.myForm.get("nickName").enable();
    } else {
         this.myForm.get("nickName").disable();
    }
}
8
vivekkurien

Je pense que la meilleure option pour ce faire est d'intégrer les champs de la forme initiale à toutes les validations et lorsque vous souhaitez désactiver et activer les champs ou les formulaires imbriqués par programmation.

Exemple: https://stackblitz.com/edit/angular-ojebff

https://stackblitz.com/edit/angular-ojebff?embed=1&file=app/input-errors-example.html

2
andy

Je n'ai pas trouvé ces solutions viables si vous avez beaucoup de champs optionnels dans un formulaire complexe.

Ce que j'ai fait est comme ça:

export class MyComponent implements AfterViewChecked {

 @ViewChildren(FormControlName) allFormControlInDOM: QueryList<FormControlName>;

 // ...

  ngAfterViewChecked(): void {
    // We must disable the controls that are not in the DOM
    // If we don't, they are used for validating the form
    if (this.allFormControlInDOM) {
      const controls: { [p: string]: AbstractControl } = this.myForm.controls;
      for (const control in controls) {
        if (controls.hasOwnProperty(control) && controls[control] instanceof FormControl) {
          const found = this.allFormControlInDOM.find((item: FormControlName) => item.name === control);
          if (found) {
            controls[control].enable();
          } else {
            controls[control].disable();
            controls[control].setValue(null);
          }
        }
      }
    }
  }

// ...

}

J'espère que ça peut aider :)

0
Klem231188