Angular fa perno su due altri prodotti molto validi, ovvero RxJS e TypeScript, per fornire la migliore esperienza di sviluppo possibile tramite le migliori tecnologie front-end presenti sulla piazza. Data la vastità del framework, in questo articolo ci limiteremo ad analizzare come gestire, a livello base, l'input dell'utente.
Molti eventi del DOM sono scatenati dalle azioni dell'utente, come il click di un link, il click di un bottone, l'inserimento del testo e così via.
Angular ci mette a disposizione un meccanismo per collegarci e reagire a tali eventi.
Nel seguente esempio vediamo come è possibile eseguire il bind di un event handler, onClickMe
, all'evento corrispondente al click di un bottone:
<button (click)="onClickMe()">Click me!</button>
Possiamo vedere che l'evento click
target è stato circondato dalle parentesi tonde, mentre dopo il segno di uguale è presente un template statement all'interno delle virgolette, che non è altro che codice JavaScript che verrà eseguito in risposta all'evento.
Quando eseguiamo il binding è bene prestare attenzione al''esection contect del template statement. Gli identificatori che possono apparire in un template statement appartengono ad un preciso contesto, solitamente il componente Angular che controlla il template:
@Component({
selector: 'app-click-me',
template: `
<button (click)="onClickMe()">Click me!</button>
{{clickMessage}}`
})
export class ClickMeComponent {
clickMessage = '';
onClickMe() {
this.clickMessage = 'You are my hero!';
}
}
Quando l'utente clicca il bottone, Anguar invoca il metodo onClickMe
del componente ClickMeComponent
.
Gli eventi del DOM sono sempre accompagnati da un payload, contenente varie informazioni che potrebbero essere utili al componente. Vediamo un esempio dove ci mettiamo in ascolto dell'evento keyup
generato da un elemento <input>
per ottenere informazioni sul testo inserito dall'utente di volta in volta:
@Component({
template: `
<input (keyup)="onKey($event)">
<p>{{values}}</p>
`
})
export class ClickMeComponent {
values = '';
onKey(event: any) {
this.values = event.target.value;
}
}
Quando l'utente preme e rilascia un tasto, avviene l'evento keyup
, e Angular provvede il corrispondente event object nella variabile $event
che viene rimbalzata al metodo onKey
. Ovviamente il valore contenuto nel box di input sarà disponibile all'interno di event.target.value
. Questo valore viene ogni volta memorizzato nella variabile d'istanza value
che è interpolata all'interno di un tag <p>
, il quale sarà quindi di volta in volta aggiornato con il suo contenuto.
Nell'esempio sopra abbiamo per semplicità forzato il parametro formale al tipo any
. Il problema è che perdiamo completamente le informazioni sul tipo in gioco, informazioni che aiutano a prevenire errori.
Ecco come tipizzare correttamente il codice:
export class ClickMeComponent {
values = '';
onKey(event: KeyboardEvent) {
this.values = (event.target as HTMLInputElement).value;
}
}
Ipotizziamo di essere interessati non alla pressione di un qualunque tasto, ma solo al tasto Enter
. Al momento l'event handler viene invocato ad ogni keyup
, ma possiamo condizionare l'azione da intraprendere controllando la proprietà keyCode
dell'event object:
export class ClickMeComponent {
values = '';
onKey(event: KeyboardEvent) {
if(event.keyCode === 13) {
this.values = (event.target as HTMLInputElement).value;
}
}
}
Un'altra strada consiste nel mettersi in ascolto dello pseudo-evento keyup.enter
. Angular invocherà l'event handler solo quando l'utente preme il taso Enter
:
@Component({
template: `
<input (keyup.enter)="onKey($event)">
<p>{{values}}</p>
`
})
export class ClickMeComponent {
values = '';
onKey(event: KeyboardEvent) {
this.values = (event.target as HTMLInputElement).value;
}
}
Abbiamo quindi visto le primitive di base per reagire agli eventi scatenati dall'utente.
Queste tecniche sono utili per progetti di piccola scala, ma diventano rapidamente prolisse quando si ha a che fare con diversi input dell'utente. Il data binding bidirezionale è un modo più elegante e compatto per gestire questi casi e Angular ci mette a disposizione la direttiva NgModel
per questo.