Component modifica-evento, personalizzazione

Component modifica-evento, personalizzazione

Il Component “vuoto” è già stato creato, funziona ed è anche indirizzabile. Bisogna ora personalizzarlo per fargli fare quello che ci serve, ovvero presentare i dati relativi ad una certa manifestazione di ballo e consentire all’utente di modificarli.

In html gli elementi chiave per l’input dei dati sono gli stessi del componente aggiunta-evento:

  • il tag <form> che racchiude i campi di input
  • il tag <input> che identifica ciascuno degli elementi di input
  • il <button> con type=submit che indica che i dati del form dovranno essere inoltrati alla funzione specificata nel tag form

Con Angular gestiamo facilmente lo scambio di informazioni bidirezionale dagli elementi html alle variabili di typescript attraverso la classe formGroup. Per questo aspetto il componente di Modifica di un evento e quello già visto della Creazione di un evento sono funzionalmente identici. Rimandiamo quindi la sua comprensione a quanto già visto.

Le grandi somiglianze proprio fra aggiunta-evento.component.ts e modifica-evento.component.ts ci offrono la possibilità di un piccolo refactoring del codice mettendo a fattor comune le definizioni di alcune costanti.

CREAZIONE DEL FILE Costanti.ts

Nella cartella app/classes mettiamo questo file contenente tutte le definizioni di costanti utili ai diversi componenti.

import { Validators } from "@angular/forms";

export class Costanti {
 
  public static RE_URL =
    "^((https?)://)?([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*" +
    "((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}" +
    "|([a-zA-Z0-9-]+.)*[a-zA-Z0-9-]+.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum" +
    "|[a-zA-Z]{2}))(:[0-9]+)*(/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$";

  public static RE_BALLI =
    "^(balboa|Balboa|lindy|Lindy|lindy hop|Lindy hop|Lindy Hop|charleston|Charleston " +
    " collegiate shag|Collegiate shag|shag|Shag|Blues|blues|Jazz|jazz|\\s|,)*$";
 
  public static RE_DATA = "^2\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$";

  public static 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: "L'indirizzo del sito deve avere un formato valido"
      }
    ],
    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"
      }
    ]
  };
 
  public static VALIDATORI_EVENTO = {
    name: [
      "",
      Validators.compose([
        Validators.required,
        Validators.minLength(3),
        Validators.maxLength(100)
      ])
    ],
    site2: [
      "",
      Validators.compose([
        Validators.required,
        Validators.pattern(Costanti.RE_URL)
      ])
    ],
    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(Costanti.RE_BALLI)
      ])
    ],
    startdate: [
      "",
      Validators.compose([
        Validators.required,
        Validators.pattern(Costanti.RE_DATA)
      ])
    ],
    stopdate: [
      "",
      Validators.compose([
        Validators.required,
        Validators.pattern(Costanti.RE_DATA)
      ])
    ]
  };
}

MODIFICA DEL FILE modifica-evento.component.ts

La struttura di questo componente  è la stessa di quello aggiunta-evento.component.ts. Dal punto di vista funzionale cambiano poche cose: 1)Prima di visualizzare il form bisogna caricare i dati già esistenti; 2) Quando i dati vengono salvati dall’utente, non dovranno essere inseriti nella nostra struttura dati, ma dovranno aggiornarla (attraverso l’invocazione del metodo modifyEvento in ExternaDataService).

Notiamo quanto diventa snello il codice grazie all’impiego di Costanti.ts.

import { Component, OnInit } from "@angular/core";

import { Router, ActivatedRoute } from "@angular/router";
import { ExternalDataService } from "../../services/external-data.service";
import { FormBuilder, FormGroup, NgForm } from "@angular/forms";
import { Costanti } from "../../classes/Costanti";

@Component({
  selector: "app-modifica-evento",
  templateUrl: "./modifica-evento.component.html",
  styleUrls: ["./modifica-evento.component.css"]
})
export class ModificaEventoComponent implements OnInit {
  eventForm: FormGroup;
  id = 0;

  form_validation_messages = Costanti.FORM_VALIDATION_MESSAGES;

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

  ngOnInit() {
    this.id = this.route.snapshot.params["id"];
    this.eventForm = this.formBuilder.group(Costanti.VALIDATORI_EVENTO);
    this.getEvento();
  }

  getEvento() {
    var data = this.externalDataService.getEvento(this.id);
    this.eventForm.setValue({
      name: data.name,
      site2: data.site2,
      country: data.country,
      town: data.town,
      styles: data.styles,
      startdate: data.startdate,
      stopdate: data.stopdate
    });
  }

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

  eventoDetails() {
    this.router.navigate(["/evento-details", this.id]);
  }
}

MODIFICA DEL FILE modifica-evento.component.html

Per dare un po’ di varietà alla grafica, nel componente di modifica mettiamo tutti i campi di input su di una riga diversa.

<div class="inner-single">
  <div>
    <div class="button-row">
      <a mat-flat-button color="primary" [routerLink]="['/']"
        ><mat-icon>list</mat-icon></a
      >
    </div>

    <mat-card class="example-card">
      <mat-card-content>
        <form
          [formGroup]="eventForm"
          (ngSubmit)="onFormSubmit(eventForm.value)"
        >
          <mat-form-field class="mat-form-field-modify">
            <table>
              <tr>
                <td>
                  <input
                    matInput
                    size="100"
                    placeholder="Nome dell'Evento"
                    formControlName="name"
                  />
                </td>
              </tr>

              <tr>
                <td>
                  <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>
                </td>
              </tr>
            </table>
          </mat-form-field>
          <br />
 
          <mat-form-field class="mat-form-field-modify">
            <table>
              <tr>
                <td>
                  <input
                    matInput
                    size="100"
                    placeholder="Sito Web"
                    formControlName="site2"
                  />
                </td>
              </tr>
              <tr>
                <td>
                  <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>
                </td>
              </tr>
            </table>
          </mat-form-field>
          <br />
          <mat-form-field class="mat-form-field-modify">
            <table>
              <tr>
                <td>
                  <input
                    matInput
                    size="100"
                    placeholder="Nazione"
                    formControlName="country"
                  />
                </td>
              </tr>
              <tr>
                <td>
                  <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>
                </td>
              </tr>
            </table>
          </mat-form-field>
          <br />
 
          <mat-form-field class="mat-form-field-modify">
            <table>
              <tr>
                <td>
                  <input
                    matInput
                    placeholder="Città"
                    formControlName="town"
                    size="100"
                  />
                </td>
              </tr>
              <tr>
                <td>
                  <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>
                </td>
              </tr>
            </table>
          </mat-form-field>
          <br />
 
          <mat-form-field class="mat-form-field-modify">
            <table>
              <tr>
                <td>
                  <input
                    matInput
                    size="100"
                    placeholder="Balli"
                    formControlName="styles"
                  />
                </td>
              </tr>
              <tr>
                <td>
                  <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>
                </td>
              </tr>
            </table>
          </mat-form-field>
          <br />
 
           <mat-form-field class="mat-form-field-modify">
            <table>
              <tr>
                <td>
                  <input
                    matInput
                    placeholder="Data di Inizio"
                    formControlName="startdate"
                    size="100"
                  />
                </td>
              </tr>
              <tr>
                <td>
                  <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>
                </td>
              </tr>
            </table>
          </mat-form-field>
          <br />
           <mat-form-field class="mat-form-field-modify">
            <table>
              <tr>
                <td>
                  <input
                    matInput
                    placeholder="Data di Fine"
                    formControlName="stopdate"
                  />
                </td>
              </tr>
 
 
             <tr>
                <td>
                  <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>
                </td>
              </tr>
            </table>
          </mat-form-field>
 
          <br />
          <div class="button-row">
            <button
              type="submit"
              [disabled]="!eventForm.valid"
              mat-flat-button
              color="primary"
            >
              <mat-icon>save</mat-icon>
            </button>
          </div>
        </form>
      </mat-card-content>
    </mat-card>
  </div>
</div>

MODIFICA DEL FILE external-data.service.ts

import { Injectable } from "@angular/core";
import { Router } from "@angular/router";

let dati_Lista_Eventi = [];
var last_event_id = 226;
 
var dati_Lista_Eventi: any[] = [
  {
    id: 13,
    name: "Swing Fastival",
    country: "United Kingdom",
    town: "Torquay, Devon ",
    site2: "http://www.swingfastival.co.uk",
    styles: "Balboa, Shag",
    startdate: "2019-11-08",
    stopdate: "2019-11-10"
  },
  {
    id: 14,
    name: "Boulevard Blues",
    country: "Belgium",
    town: "Hasselt",
    site2: "www.boulevardblues.be ",
    styles: "Blues",
    startdate: "2019-11-08",
    stopdate: "2019-11-11"
  },
  {
    id: 124,
    name: "Montpellier Balboa Rendez-Vous",
    country: "France",
    town: "Montpellier",
    site2: "http://www.swingcatcie.com/montpellier-balboa-rendezvous/",
    styles: "Balboa, Shag",
    startdate: "2020-02-14",
    stopdate: "2020-02-16"
  },
  {
    id: 125,
    name: "Holy lollies",
    country: "France",
    town: "Strasbourg",
    site2: "http://www.holylollies.fr",
    styles: "Balboa",
    startdate: "2020-02-14",
    stopdate: "2020-02-16"
  },
  {
    id: 208,
    name: "Black Forest Hop",
    country: "Germany",
    town: "Freiburg",
    site2: "http://www.blackforesthop.com",
    styles: "Lindy Hop",
    startdate: "2020-06-05",
    stopdate: "2020-06-07"
  },
  {
    id: 223,
    name: "JazzOut SwingFest",
    country: "Netherlands",
    town: "Nijmegen",
    site2: "http://www.jazzoutswingfest.com/",
    styles: "Jazz, Lindy Hop",
    startdate: "2020-08-28",
    stopdate: "2020-08-30"
  },
  {
    id: 224,
    name: "Shirt Tail Stompers 10 Year Aniversary Weekend",
    country: "Lithuania",
    town: "Vilnius",
    site2: "https://www.facebook.com/events/2981610321881346/",
    styles: "Balboa, Charleston, Jazz, Lindy Hop, Shag",
    startdate: "2020-08-28",
    stopdate: "2020-08-30"
  },
  {
    id: 225,
    name: "Swinging and Sail",
    country: "Greece",
    town: "Athens - Ithaca",
    site2: "http://www.swingnsail.com",
    styles: "Lindy Hop",
    startdate: "2020-08-28",
    stopdate: "2020-09-05"
  },
  {
    id: 226,
    name: "Madrid in Pulse",
    country: "Spain",
    town: "Madrid",
    site2: "http://www.madridinpulse.es/?lang=en",
    styles: "Balboa",
    startdate: "2020-09-04",
    stopdate: "2020-09-06"
  }
];
 
@Injectable({
  providedIn: "root"
})
export class ExternalDataService {
  constructor(private router: Router) {}
 
  getEventi() {
    return dati_Lista_Eventi;
  }
 
  getEvento(id: number) {
    for (let i in dati_Lista_Eventi) {
      if (dati_Lista_Eventi[i].id == id) {
        return dati_Lista_Eventi[+i];
      }
    }
    return null;
  }
 
  deleteEvento(id: number) {
    let pos: number = -1;
    for (let i in dati_Lista_Eventi) {
      if (dati_Lista_Eventi[i].id === id) {
        pos = +i;
      }
    }
    if (pos !== -1) {
      dati_Lista_Eventi.splice(pos, 1);
    }
  }
 
  addEvento(form) {
    if (!form.site2.includes("http")) {
      form.site2 = "http://" + form.site2;
    }
    last_event_id += 1;
    dati_Lista_Eventi.push({
      id: last_event_id,
      name: form.name,
      country: form.country,
      town: form.town,
      site2: form.site2,
      styles: form.styles,
      startdate: form.startdate,
      stopdate: form.stopdate
    });
  }
 
  modifyEvento(id, form) {
    if (!form.site2.includes("http")) {
      form.site2 = "http://" + form.site2;
    }
    for (let i in dati_Lista_Eventi) {
      if (dati_Lista_Eventi[i].id == id) {
        dati_Lista_Eventi[i] = form;
        dati_Lista_Eventi[i].id = id;
        break;
      }
    }
  }
 
}

MODIFICA DEL FILE aggiunta-evento.component.ts

Grazie alla classe Costanti,  possiamo rendere più leggibile anche il codice in questo componente:

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";
import { Costanti } from "../../classes/Costanti";

@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 Costanti.FORM_VALIDATION_MESSAGES;

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

  ngOnInit() {
    this.eventForm = this.formBuilder.group(Costanti.VALIDATORI_EVENTO);
  }

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

Sorry, the comment form is closed at this time.