Component aggiunta-evento, validazioni

Component aggiunta-evento, validazioni

Ora che sappiamo come gestire un form di input, dobbiamo anche imparare come validare i dati inseriti dall’utente e segnalargli se non corrispondono ai nostri criteri. Dobbiamo cioè fare la validazione dell’input.

MODIFICA DEL FILE aggiunta-evento-component.ts

Gestire la validazione dell’input di una videata gestita con i formGroup di Angular è molto semplice. Quando si costruisce il form con formBuilder.group(..) per ciascuna delle variabili del form non si definisce solo il valore di inizializzazione bensì anche l’elenco dei suoi validatori. Per farlo dobbiamo importare Validators, farà il grosso del lavoro per noi;

Nel metodo ngOnInit, alle inizializzazioni delle variabili associate al form, aggiungiamo anche i validatori che riteniamo opportuni, campo per campo. Ad esempio tutti i campi sono obbligatori, quindi bisogna utilizzare il validatore required. Oltre alla possibile personalizzazione di ciascun validatore, se ne possono usare più d’uno contemporaneamente. L’elenco dei validatori possibili è disponibile nella documentazione ufficiale 

E’ possibile aggiungere anche un validatore personale, quando quelli disponibili non vengano ritenuti sufficienti e adatti alle nostre esigenze. Tra i validatori più flessibili, per i controlli formali, abbiamo deciso di impiegare pattern, ovvero quello che verifica che l’input inserito soddisfi l’ espressione regolare indicata. Le regular expressions, meritano una breve digressione a parte.

Andremo a definire a livello di classe, la variabile json form_validation_messages. In essa,  per ciascuna delle variabili in input, è esplicitata la corrispondenza validatore_insoddisfatto –> messaggio_di_errore.

import { Component, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { ExternalDataService } from "../../services/external-data.service";
import { FormBuilder, FormGroup, NgForm, Validators } from "@angular/forms";

@Component({
  selector: "aggiunta-evento-add",
  templateUrl: "./aggiunta-evento.component.html",
  styleUrls: ["./aggiunta-evento.component.css"]
})
export class AggiuntaEventoComponent implements OnInit {
  eventForm: FormGroup;
  form_validation_messages = {
    name: [
      { type: "required", message: "Il nome dell'evento è obbligatorio" },
      {
        type: "minlength",
        message: "Il nome dell'evento deve avere almeno 3 caratteri"
      },
      {
        type: "maxlength",
        message: "Il nome dell'evento non deve superare i 100 caratteri"
      }
    ],
    site2: [
      { type: "required", message: "Il sito dell'evento è obbligatorio" },
      {
        type: "pattern",
        message: "Inserire l'indirizzo web del sito"
      }
    ],
    country: [
      { type: "required", message: "Il nome della nazione è  obbligatorio" },
      {
        type: "minlength",
        message: "Il nome della nazione deve avere almeno 3 caratteri"
      },
      {
        type: "maxlength",
        message: "Il nome della nazione non deve superare i 30 caratteri"
      }
    ],
    town: [
      { type: "required", message: "Il nome della città è obbligatorio" },
      {
        type: "minlength",
        message: "Il nome della città deve avere almeno 3 caratteri"
      },
      {
        type: "maxlength",
        message: "Il nome della città non deve superare i 30 caratteri"
      }
    ],
    styles: [
      {
        type: "required",
        message: "Specificare gli stili di ballo è obbligatorio"
      },
      {
        type: "minlength",
        message: "Gli stili di ballo devono avere almeno 3 caratteri"
      },
      {
        type: "maxlength",
        message: "Gli stili di ballo non devono superare i 30 caratteri"
      },
      {
        type: "pattern",
        message:
          "Gli stili di ballo (solo swing) possono essere separati da virgole"
      }
    ],
    startdate: [
      { type: "required", message: "Le date dell'evento sono obbligatorie" },
      {
        type: "pattern",
        message: "Le date devono avere il formato aaaa-mm-gg"
      }
    ],
    stopdate: [
      { type: "required", message: "Le date dell'evento sono obbligatorie" },
      {
        type: "pattern",
        message: "Le date devono avere il formato aaaa-mm-gg"
      }
    ]
  };

  constructor(
    private router: Router,
    private externalDataService: ExternalDataService,
    private formBuilder: FormBuilder
  ) {}

  ngOnInit() {
    this.eventForm = this.formBuilder.group({
      name: [
        "",
        Validators.compose([
          Validators.required,
          Validators.minLength(3),
          Validators.maxLength(100)
        ])
      ],
      site2: [
        "",
        Validators.compose([
          Validators.required,
          Validators.pattern(
            "^(https?://)?([a-z.-]+).([a-z.]{2,6})([/w .-]*)*/?$"
          )
        ])
      ],
      country: [
        "",
        Validators.compose([
          Validators.required,
          Validators.minLength(3),
          Validators.maxLength(30)
        ])
      ],
      town: [
        "",
        Validators.compose([
          Validators.required,
          Validators.minLength(3),
          Validators.maxLength(30)
        ])
      ],
      styles: [
        "",
        Validators.compose([
          Validators.required,
          Validators.minLength(3),
          Validators.maxLength(70),
          Validators.pattern(
            "^(balboa|Balboa|lindy|Lindy|lindy hop|Lindy hop|charleston|Charleston|collegiate shag|Collegiate shag|shag|Shag|\\s|,)*$"
          )
        ])
      ],
      startdate: [
        "",
        Validators.compose([
          Validators.required,
          Validators.pattern("^\\d{4}-\\d{2}-\\d{2}$")
        ])
      ],
      stopdate: [
        "",
        Validators.compose([
          Validators.required,
          Validators.pattern("^2\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$")
        ])
      ]
    });
  }

  onFormSubmit(form: NgForm) {
    this.externalDataService.addEvento(form);
    this.router.navigate(["/"]);
  }
}

 

MODIFICA DEL FILE aggiunta-evento-component.html

Abbiamo aggiunto per ogni campo di input (<mat-form-field>) anche una sezione <mat-error>. Viene eseguito un loop (*ngFor) per ogni tipo di validatore definito con i suoi controlli, seguiti dall’eventuale corrispondente messaggio di errore. Perchè il validatore venga eseguito il campo deve essere “sporcato”, ovvero deve essere almeno raggiunto da un tab da tastiera o da un click del mouse ( eventForm.get(‘xyz’).dirty || eventForm.get(‘xyz’).touched ).

Abbiamo aggiunto al bottone di submit del form la disabilitazione finchè in tutti i campi precendenti non siano stati inseriti valori validi. ([disabled]=”!eventForm.valid”)

<div class="inner-single">
  <div class="container mat-elevation-z8">
    <span>
      <div class="button-row">
        <a mat-flat-button color="primary" [routerLink]="['/']"
          ><mat-icon>list</mat-icon></a
        >
      </div>
    </span>
    <mat-card class="example-card">
      <form [formGroup]="eventForm" (ngSubmit)="onFormSubmit(eventForm.value)">
        <mat-form-field>
          <input
            matInput
            placeholder="Nome dell'Evento"
            formControlName="name"
          />
          <mat-error *ngFor="let validation of form_validation_messages.name">
            <mat-error
              class="error-message"
              *ngIf="
                eventForm.get('name').hasError(validation.type) &&
                (eventForm.get('name').dirty || eventForm.get('name').touched)
              "
              >{{ validation.message }}
            </mat-error>
          </mat-error>
        </mat-form-field>

        <mat-form-field>
          <input
            matInput
            placeholder="Sito Web"
            formControlName="site2"
            name="site"
            id="site2"
            type="text"
          />
          <mat-error *ngFor="let validation of form_validation_messages.site2">
            <mat-error
              class="error-message"
              *ngIf="
                eventForm.get('site2').hasError(validation.type) &&
                (eventForm.get('site2').dirty || eventForm.get('site2').touched)
              "
              >{{ validation.message }}
            </mat-error>
          </mat-error>
        </mat-form-field>
        <br /><br />

        <mat-form-field>
          <input matInput placeholder="Nazione" formControlName="country" />
          <mat-error
            *ngFor="let validation of form_validation_messages.country"
          >
            <mat-error
              class="error-message"
              *ngIf="
                eventForm.get('country').hasError(validation.type) &&
                (eventForm.get('country').dirty ||
                  eventForm.get('country').touched)
              "
              >{{ validation.message }}
            </mat-error>
          </mat-error>
        </mat-form-field>
 
       <mat-form-field>
          <input matInput placeholder="Città" formControlName="town" />
          <mat-error *ngFor="let validation of form_validation_messages.town">
            <mat-error
              class="error-message"
              *ngIf="
                eventForm.get('town').hasError(validation.type) &&
                (eventForm.get('town').dirty || eventForm.get('town').touched)
              "
              >{{ validation.message }}
            </mat-error>
          </mat-error>
        </mat-form-field>
 
        <mat-form-field>
          <input matInput placeholder="Balli" formControlName="styles" />
          <mat-error *ngFor="let validation of form_validation_messages.styles">
            <mat-error
              class="error-message"
              *ngIf="
                eventForm.get('styles').hasError(validation.type) &&
                (eventForm.get('styles').dirty ||
                  eventForm.get('styles').touched)
              "
              >{{ validation.message }}
            </mat-error>
          </mat-error>
        </mat-form-field>
        <br /><br />

 

        <mat-form-field>
          <input
            matInput
            placeholder="Data di Inizio"
            formControlName="startdate"
          />
          <mat-error
            *ngFor="let validation of form_validation_messages.startdate"
          >
            <mat-error
              class="error-message"
              *ngIf="
                eventForm.get('startdate').hasError(validation.type) &&
                (eventForm.get('startdate').dirty ||
                  eventForm.get('startdate').touched)
              "
              >{{ validation.message }}
            </mat-error>
          </mat-error>
        </mat-form-field>

 

        <mat-form-field class="example-full-width">
          <input
            matInput
            placeholder="Data di Fine"
            formControlName="stopdate"
          />
          <mat-error
            *ngFor="let validation of form_validation_messages.stopdate"
          >
            <mat-error
              class="error-message"
              *ngIf="
                eventForm.get('stopdate').hasError(validation.type) &&
                (eventForm.get('stopdate').dirty ||
                  eventForm.get('stopdate').touched)
              "
              >{{ validation.message }}
            </mat-error>
          </mat-error>
        </mat-form-field>

 

        <br /><br /><br />
        <div>
          <button
            type="submit"
            [disabled]="!eventForm.valid"
            mat-flat-button
            color="primary"
          >
            <mat-icon>save</mat-icon>
          </button>
        </div>
      </form>
    </mat-card>
  </div>
</div>
No Comments

Sorry, the comment form is closed at this time.