5 Eventi nativi

Vediamo come gestire gli eventi nei componenti di angular.

<td>
 <button>CANCELLA</button>
</td>

normalmente potremmo inserire l’evento click sul bottone usando il classico javascript onclick

<button onclick="alert('ciao')">CANCELLA</button>

Questo metodo non funzionerebbe se dovessi richiamare un metodo presente nella classe UserComponent() , come per esempio una funzione deleteUser() dentro l’ ngOnInit() che riceverà user come parametro.

ngOnInit() {
 deleteUser(user) {
  alert(user.cognome);
 }
}

Con l’evento nativo javascript onclick nell’HTML, non riuscirei a richiamare il metodo deleteUser() presente nel componente, perchè si tratterebbe di un altro file, a meno che non aggiungo la funzione nel file HTML, ma non è quello che vogliamo perchè vogliamo richiamare funzioni della classe.

In angular per gestire gli eventi bisogna richiamare l’evento tra parentesi tonde per poi fargli richiamare metodi e proprietà della classe. Quindi il metodo onclick=”” diventa (click). In sostanza ho tolto on e messo le tonde passando come parametro user alla funzione

<button (click)="deleteUser(user)">CANCELLA</button>

adesso l’evento funziona perfettamente richiamando il metodo presente nella classe componente.

In effetti si potrebbe non passare il parametro user al metodo, in quanto la variabile user è già dichiarata dal decoratore @input del componente e non vi è necessità di passarla nel metodo dell’evento e della classe, aggiungiamo anche il tipo any alla variabile

@input('user-data') user: any;

basta solo richiamarla col this, quindi il codice dell’evento nativo nel file HTML e del metodo del componente diventano:

<button (click)="deleteUser()">CANCELLA</button>

deleteUser() {
 alert(this.user.cognome);
}

Richiamiamo ora un metodo che cancella realmente i dati dall’array tipo splice(), ma spostiamo la logica nel servizio user.service.ts .

Mettiamo i dati nell’array users del servizio che passeremo al metodo deleUser che andremo a creare sempre nel servizio

deleteUser(user: any) {
 let indice = this.users.indexOf(user);
 if (indice >= 0) {
  this.users.splice(indice, 1);
  }
}

Ho utilizzato il metodo js indexOf() che restituisce l’indice di un elemento di un oggetto oppure restituisce -1 se non lo trova, quindi con un if vediamo se è maggiore di zero utilizzando il metodo js per gli array splice() eliminiamo quell’elemto passandogli come primo parametro l’indice come prima posizione di eliminazione e 1 come secondo parametro che indica quanti elemnti eliminare a partire da quella posizione.

Ecco la classe del users.component.ts dove nel costruttore metto la variabile injectable di tipo private

export class UsersComponent implements OnInit {
 users = [];
 private servizio;
 constructor( private service: UserService) {
 this.servizio = service;
 }
ngOnInit() {
 this.users = this.servizio.getUsers();
 }
}

e quella di user

export class UserComponent implements OnInit {
@Input('user-data') user: any;
constructor(private userService:UserService) {
}
deleteUser() {
 this.userService.deleteUser(this.user);
 }
}

@output

Ora che abbiamo ottimizzato e diviso i compiti tra componenti e servizio vogliamo delegare il compito al componente parent users di cancellazione dei dati. Per far questo esiste una classe apposita in angular, ma prima dobbiamo inviare l’evento verso l’esterno dichiarando un decoratore di uscita @output a cui mettiamo facoltativamente un’etichetta come avevamo fatto per @input

@Output('onDeleteUser') userDeleted;

Eventemetter() / emit()

quindi onDeleteUser diventa il nome pubblico col quale richiamare l’evento, ma dobbiamo anche inizializzare la variabile userDeleted come nuovo oggetto della classe predefinita di angular EventEmetter()

@Output('onDeleteUser') userDeleted = new EventEmitter();

automaticamente dovrebbe essere stato importato dall’ide sia Output che la classe EventEmetter, aggiungerlo qualora non lo fosse

import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';

a questo punto nella funzione precedentemente creata deleteUser(), sostituiamo il vecchio codice utilizzando il metodo predefinito della classe eventEmetter emit()

deleteUser() {
 this.userDeleted.emit(this.user);
}

al metodo emit() passerò i dati in ingresso this.user.

Adesso l’evento è scatenato, però userDelete che all’esterno si chiama onDeleteUser grazie all’etichetta assegnata nel decoratore @output, non è ancora ascoltato da nessuna parte, dobbiamo ascoltarlo nel file HTML users creando l’evento tra parentesi tonde perhè è in uscita, che chiamerà un metodo onDeleteUsers() che andiamo a creare.

(onDeleteUser) = "onDeleteUsers($event)"

Il valore in uscita viene passato dal nostro metodo tramite una variabile speciale già presente in angular che si chiama $event.

Creiamo il metodo onDeleteUsers() con un alert per provare se tutto funziona

onDeleteUsers(user){
  alert(user.nome);
}

Ora che tutto funziona, abbiamo che l’elementofiglio user sta emettendo un evento catturato dal padre che è in ascolto e riceve il valore passato grazie a $event.

Sostituiamo l’alert chiamando il service (quindi col this) dichiarato già nella stessa classe, richiamando il metodo deleteUser() sul servizio.

onDeleteUsers(user: any){
 this.servizio.deleteUser(user);
}