18 KiB
Creazione di un'App Bancaria Parte 2: Creazione di un form di accesso e registrazione
Quiz Pre-Lezione
Introduzione
In quasi tutte le moderne app web, si può creare un account per avere il proprio spazio privato. Poiché più utenti possono accedere a un'app web contemporaneamente, è necessario un meccanismo per archiviare i dati personali di ciascun utente separatamente e selezionare le informazioni da visualizzare. Non verrà trattato come gestire l'identità dell'utente in modo sicuro poiché si tratta di un argomento ampio di per sé, ma ci si assicurerà che ogni utente sia in grado di creare uno (o più) conto bancario nella app.
In questa parte si utilizzeranno form HTML per aggiungere login e registrazione all'app. Si vedrà come inviare i dati a un'API del server a livello di programmazione e, infine, come definire le regole di convalida di base per gli input dell'utente.
Prerequisito
È necessario aver completato i modelli HTML e il routing dell'app web per questa lezione. È inoltre necessario installare Node.js ed eseguirel'API del server in locale in modo da poter inviare dati per creare account.
Si può verificare che il server funzioni correttamente eseguendo questo comando in un terminale:
curl http://localhost:5000/api
# -> dovrebbe restituire "Bank API v1.0.0" come risultato
Form e controlli
L'elemento <form>
incapsula una sezione di un documento HTML in cui l'utente può inserire e inviare dati con controlli interattivi. Esistono tutti i tipi di controlli dell'interfaccia utente (UI) che possono essere utilizzati all'interno di un form, i più comuni sono gli elementi <input>
e <button>
.
Esistono molti tipi diversi di <input>
, ad esempio per creare un campo in cui l'utente può inserire il proprio nome utente si può utilizzare:
<input id="username" name="username" type="text">
L'attributo name
verrà utilizzato come nome della proprietà quando verranno inviati i dati del form. L'attributo id
viene utilizzato per associare un'etichetta (<label>
) al relativo controllo nel form.
Si dia un'occhiata all'intero elenco di tipi di
<input>
e altri controlli del form per avere un'idea di tutti gli elementi nativi dell'interfaccia utente che si possono utilizzare durante la creazione della propria interfaccia utente.
✅ Si noti che <input>
è un elemento vuoto su cui non si dovrebbe aggiungere un tag di chiusura corrispondente. È comunque possibile utilizzare la notazione a chiusura automatica <input/>
, ma non è richiesta.
L'elemento <button>
all'interno di un form è un po' speciale. Se non si specifica il suo attributo di tipo (type
) , invierà automaticamente i dati del form al server quando viene premuto. Ecco i possibili valori di type
:
submit
: l'impostazione predefinita all'interno di un<form>
, il pulsante attiva l'azione di invio del form.reset
: il pulsante ripristina tutti i controlli del form ai valori iniziali.button
: non assegna un comportamento predefinito quando viene premuto il pulsante. È quindi possibile assegnargli azioni personalizzate utilizzando JavaScript.
Attività
Si comincia aggiungendo un form al modello di accesso login
. Servirà di un campo username per il nome utente e di un pulsante Login .
<template id="login">
<h1>Bank App</h1>
<section>
<h2>Login</h2>
<form id="loginForm">
<label for="username">Username</label>
<input id="username" name="user" type="text">
<button>Login</button>
</form>
</section>
</template>
Se si guarda più attentamente, si può notare che è stato aggiunto anche un elemento <label>
(etichetta). Gli elementi <label>
vengono utilizzati per aggiungere un nome ai controlli dell'interfaccia utente, come il campo username. Le etichette sono importanti per la leggibilità dei form, ma offrono anche vantaggi aggiuntivi:
- Associaer un'etichetta a un controllo in un form, aiuta gli utenti che utilizzano tecnologie assistite (come unlettore di schremo) a capire quali dati dovrebbero fornire.
- È possibile fare clic sull'etichetta per portare direttamente il focus sull'input associato, rendendolo più facile da raggiungere su dispositivi basati su touch screen.
L'accessibilità sul Web è un argomento molto importante che spesso viene trascurato. Grazie agli elementi HTML semantici non è difficile creare contenuti accessibili se usati correttamente. Si può leggere di più sull'accessibilità per evitare errori comuni e diventare uno sviluppatore responsabile.
Ora si aggiungerà un secondo modulo per la registrazione, appena sotto il precedente:
<hr/>
<h2>Register</h2>
<form id="registerForm">
<label for="user">Username</label>
<input id="user" name="user" type="text">
<label for="currency">Currency</label>
<input id="currency" name="currency" type="text" value="$">
<label for="description">Description</label>
<input id="description" name="description" type="text">
<label for="balance">Current balance</label>
<input id="balance" name="balance" type="number" value="0">
<button>Register</button>
</form>
Utilizzando l'attributo value
si può impostare un valore predefinito per un dato input. Si noti inoltre che l'input per il saldo(balance
) ha il tipo number
(numero). Sembra diverso dagli altri input? Provare a interagire con esso.
✅ Si può navigare e interagire con i form utilizzando solo una tastiera? E come si pensa di fare?
Invio dei dati al server
Ora che si ha un'interfaccia utente funzionale, il passaggio successivo è inviare i dati al server. Fare un rapido test utilizzando il codice attuale: cosa succede se si fa clic sul pulsante Login o Register ?
Si è notato il cambiamento nella sezione URL del proprio browser?
L'azione predefinita per un <form>
consiste nell'inviare il form all'URL del server corrente utilizzando il metodo GET, aggiungendo i dati del modulo direttamente all'URL. Questo metodo presenta però alcuni difetti:
- I dati inviati sono di dimensioni molto limitate (circa 2000 caratteri)
- I dati sono direttamente visibili nell'URL (non eccezionale per le password)
- Non funziona con i caricamenti di file
Ecco perché si può cambiare e utilizzare il metodo POST che invia i dati del modulo al server nel corpo della richiesta HTTP, senza nessuna delle limitazioni precedenti.
Sebbene POST sia il metodo più comunemente utilizzato per inviare i dati, in alcuni scenari specifici è preferibile utilizzare il metodo GET, ad esempio quando si implementa un campo di ricerca.
Attività
Aggiungere le proprietà action
e method
al form di registrazione:
<form id="registerForm" action="//localhost:5000/api/accounts" method="POST">
Provare ora a registrare un nuovo account con il proprio nome. Dopo aver fatto clic sul pulsante Register si dovrebbe vedere qualcosa del genere:
Se tutto va bene, il server dovrebbe rispondere alla richiesta con una risposta JSON contenente i dati dell'account che è stato creato.
✅ Provare una nuova registrazione con lo stesso nome. Che cosa accade?
Invio di dati senza ricaricare la pagina
Come probabilmente si è notato, c'è un piccolo problema con l'approccio appena usato: quando si invia il modulo, si esce dalla propria app e il browser reindirizza all'URL del server. Si sta cercando qui di evitare tutti i ricaricamenti delle pagine con quest app web, poiché si sta creando un'applicazione a pagina singola (SPA).
Per inviare i dati del modulo al server senza forzare il ricaricamento di una pagina, si deve utilizzare il codice JavaScript. Invece di inserire un URL nella proprietà action
di un <form>
, si può utilizzare qualsiasi codice JavaScript anteposto dalla stringa javascript:
per eseguire un'azione personalizzata. Usarlo significa anche che si dovranno implementare alcune attività che erano state precedentemente eseguite automaticamente dal browser:
- Recuperare i dati del form
- Convertire e codificare i dati del form in un formato adatto
- Creare la richiesta HTTP e inviarla al server
Attività
Sostituire action
nel form di registrazione con:
<form id="registerForm" action="javascript:register()">
Aprire app.js
aggiungere una nuova funzione denominata register
:
function register() {
const registerForm = document.getElementById('registerForm');
const formData = new FormData(registerForm);
const data = Object.fromEntries(formData);
const jsonData = JSON.stringify(data);
}
Qui si recupera l'elemento form utilizzando getElementById()
e si utilizza il metodo di supporto FormData per estrarre i valori dai controlli del forma come un insieme di coppie chiave/valore. Quindi si convertono i dati in un oggetto normale utilizzando Object.fromEntries()
e infine si serializzano i dati in JSON, un formato comunemente utilizzato per lo scambio di dati sul web.
I dati sono ora pronti per essere inviati al server. Creare una nuova funzione denominata createAccount
:
async function createAccount(account) {
try {
const response = await fetch('//localhost:5000/api/accounts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: account
});
return await response.json();
} catch (error) {
return { error: error.message || 'Unknown error' };
}
}
Cosa fa questa funzione? Per prima cosa notare la parola chiave async
. Ciò significa che la funzione contiene codice che verrà eseguito in modo asincrono. Quando viene utilizzato insieme alla parola chiave await
, consente di attendere l'esecuzione del codice asincrono, come l'attesa della risposta del server qui, prima di continuare.
Ecco un breve video sull'utilizzo di async/await
:
Fare clic sull'immagine sopra per un video su async/await.
Si usa l'API fetch()
per inviare dati JSON al server. Questo metodo richiede 2 parametri:
- L'URL del server, quindi rimettere
//localhost:5000/api/accounts
qui. - Le impostazioni della richiesta. È qui che si imposta il metodo su
POST
e si fornisce il corpo (body
) della richiesta. Dato che si inviano dati JSON al server, si deve anche impostare l'intestazioneContent-Type
suapplication/json
in modo che il server sappia come interpretare il contenuto.
Poiché il server risponderà alla richiesta con JSON, si può utilizzare await response.json()
per analizzare il contenuto JSON e restituire l'oggetto risultante. Notare che questo metodo è asincrono, quindi si usa la parola chiave await
qui prima di tornare per assicurarsi che vengano rilevati anche eventuali errori durante l'analisi.
Ora aggiungere del codice alla funzione di register
per chiamare createAccount()
:
const result = await createAccount(jsonData);
Poiché qui si usa la parola chiave await
, si deve aggiungere la parola chiave async
prima della funzione di registrazione
async function register() {
Infine, aggiungere alcuni log per verificare il risultato. La funzione finale dovrebbe essere simile a questa:
async function register() {
const registerForm = document.getElementById('registerForm');
const formData = new FormData(registerForm);
const jsonData = JSON.stringify(Object.fromEntries(formData));
const result = await createAccount(jsonData);
if (result.error) {
return console.log('An error occured:', result.error);
}
console.log('Account created!', result);
}
È stato un po' lungo ma si è arrivati! Se si apre strumenti di sviluppo del browser e si prava a registrare un nuovo account, non si dovrebbe vedere alcun cambiamento nella pagina web ma apparirà un messaggio nella console che conferma che tutto funziona.
✅ Si pensa che i dati vengano inviati al server in modo sicuro? E se qualcuno fosse in grado di intercettare la richiesta? Si possono leggere informazioni su HTTPS per saperne di più sulla comunicazione sicura dei dati.
Convalida dati
Se si prova a registrare un nuovo account senza prima impostare un nome utente, si può vedere che il server restituisce un errore con codice di stato 400 Bad Request, (richiesta non valida)
Prima di inviare i dati a un server è buona norma convalidare i dati del modulo in anticipo quando possibile, per assicurarsi di inviare una richiesta valida. I controlli dei form HTML5 forniscono la convalida incorporata utilizzando vari attributi:
requested
: il campo deve essere compilato altrimenti il modulo non può essere inviato.minlength
emaxlength
: definisce il numero minimo e massimo di caratteri nei campi di testo.min
emax
: definisce il valore minimo e massimo di un campo numerico.type
: definisce il tipo di dati attesi, comenumber
,email
,file
o altri tipi incorporati. Questo attributo può anche modificare il rendering visivo del form.pattern
: permette di definire un modello di espressione regolare per verificare se i dati inseriti sono validi o meno.
Suggerimento: si può personalizzare l'aspetto dei controlli del form a seconda che siano validi o meno utilizzando le pseudo-classi CSS
:valid
e:invalid
.
Attività
Ci sono 2 campi obbligatori per creare un nuovo account valido, nome utente (username) e la valuta (currency), gli altri campi sono opzionali. Aggiornare l'HTML del form, utilizzando sia l'attributo required
che il testo nell'etichetta del campo in questo modo:
<label for="user">Username (required)</label>
<input id="user" name="user" type="text" required>
...
<label for="currency">Currency (required)</label>
<input id="currency" name="currency" type="text" value="$" required>
Sebbene questa particolare implementazione del server non imponga limiti specifici sulla lunghezza massima dei campi, è sempre buona norma definire limiti ragionevoli per qualsiasi voce di testo inserita dell'utente.
Aggiungere un attributo maxlength
ai campi di testo:
<input id="user" name="user" type="text" maxlength="20" required>
...
<input id="currency" name="currency" type="text" value="$" maxlength="5" required>
...
<input id="description" name="description" type="text" maxlength="100">
Ora se si preme il pulsante Register e un campo non rispetta una regola di convalida che è stata definita, si dovrebbe vedere qualcosa del genere:
La convalida come questa eseguita prima di inviare qualsiasi dato al server è chiamata convalida lato client . Tenere presente che non è sempre possibile eseguire tutti i controlli senza inviare i dati. Ad esempio, non si può verificare qui se esiste già un account con lo stesso nome utente senza inviare una richiesta al server. La convalida aggiuntiva eseguita sul server è denominata convalida lato server .
Di solito devono essere implementate entrambe; mentre l'utilizzo della convalida lato client migliora l'esperienza dell'utente fornendo un feedback immediato all'utente, la convalida lato server è fondamentale per assicurarsi che i dati utente da manipolare siano validi e sicuri.
🚀 Sfida
Mostrare un messaggio di errore nell'HTML se l'utente esiste già.
Ecco un esempio di come può apparire la pagina di accesso finale dopo l'applicazione di un po' di stile:
Quiz Post-Lezione
Revisione e Auto Apprendimento
Gli sviluppatori sono diventati molto creativi nei loro sforzi di costruzione di form, in particolare per quanto riguarda le strategie di convalida. Scoprire i diversi flussi di form cercando su CodePen; si riescono a trovare dei form interessanti e stimolanti?