|
3 weeks ago | |
---|---|---|
.. | ||
README.md | 3 weeks ago | |
assignment.md | 3 weeks ago |
README.md
Construirea unei aplicații bancare Partea 3: Metode de preluare și utilizare a datelor
Chestionar înainte de curs
Introducere
La baza fiecărei aplicații web se află datele. Datele pot lua multe forme, dar scopul lor principal este întotdeauna să afișeze informații utilizatorului. Pe măsură ce aplicațiile web devin din ce în ce mai interactive și complexe, modul în care utilizatorul accesează și interacționează cu informațiile a devenit o parte esențială a dezvoltării web.
În această lecție, vom vedea cum să preluăm date de pe un server în mod asincron și să folosim aceste date pentru a afișa informații pe o pagină web fără a reîncărca HTML-ul.
Prerechizite
Trebuie să fi construit Formularul de autentificare și înregistrare al aplicației web pentru această lecție. De asemenea, trebuie să instalați Node.js și să rulați API-ul serverului local pentru a obține datele contului.
Puteți testa dacă serverul funcționează corect executând această comandă într-un terminal:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
AJAX și preluarea datelor
Site-urile web tradiționale actualizează conținutul afișat atunci când utilizatorul selectează un link sau trimite date printr-un formular, reîncărcând întreaga pagină HTML. De fiecare dată când trebuie încărcate date noi, serverul web returnează o pagină HTML complet nouă care trebuie procesată de browser, întrerupând acțiunea curentă a utilizatorului și limitând interacțiunile în timpul reîncărcării. Acest flux de lucru este cunoscut și sub denumirea de Aplicație Multi-Pagină sau MPA.
Când aplicațiile web au început să devină mai complexe și interactive, a apărut o tehnică nouă numită AJAX (JavaScript și XML asincron). Această tehnică permite aplicațiilor web să trimită și să preia date de pe un server în mod asincron folosind JavaScript, fără a reîncărca pagina HTML, rezultând actualizări mai rapide și interacțiuni mai fluide pentru utilizator. Când sunt primite date noi de la server, pagina HTML curentă poate fi actualizată cu JavaScript folosind API-ul DOM. În timp, această abordare a evoluat în ceea ce se numește acum o Aplicație Single-Page sau SPA.
Când AJAX a fost introdus pentru prima dată, singurul API disponibil pentru preluarea datelor în mod asincron era XMLHttpRequest
. Dar browserele moderne implementează acum și API-ul mai convenabil și mai puternic Fetch
, care folosește promisiuni și este mai potrivit pentru manipularea datelor JSON.
Deși toate browserele moderne acceptă
Fetch API
, dacă doriți ca aplicația dvs. web să funcționeze pe browsere mai vechi, este întotdeauna o idee bună să verificați mai întâi tabelul de compatibilitate pe caniuse.com.
Sarcină
În lecția anterioară am implementat formularul de înregistrare pentru a crea un cont. Acum vom adăuga cod pentru autentificarea folosind un cont existent și pentru preluarea datelor acestuia. Deschideți fișierul app.js
și adăugați o nouă funcție login
:
async function login() {
const loginForm = document.getElementById('loginForm')
const user = loginForm.user.value;
}
Aici începem prin a prelua elementul formularului cu getElementById()
, iar apoi obținem numele de utilizator din câmpul de intrare cu loginForm.user.value
. Fiecare control al formularului poate fi accesat prin numele său (setat în HTML folosind atributul name
) ca proprietate a formularului.
În mod similar cu ceea ce am făcut pentru înregistrare, vom crea o altă funcție pentru a efectua o cerere către server, dar de data aceasta pentru a prelua datele contului:
async function getAccount(user) {
try {
const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user));
return await response.json();
} catch (error) {
return { error: error.message || 'Unknown error' };
}
}
Folosim API-ul fetch
pentru a solicita datele în mod asincron de la server, dar de data aceasta nu avem nevoie de alți parametri în afară de URL-ul pe care să-l apelăm, deoarece doar interogăm date. Implicit, fetch
creează o cerere HTTP GET
, ceea ce este exact ceea ce căutăm aici.
✅ encodeURIComponent()
este o funcție care scapă caracterele speciale pentru URL. Ce probleme am putea avea dacă nu apelăm această funcție și folosim direct valoarea user
în URL?
Acum să actualizăm funcția noastră login
pentru a folosi getAccount
:
async function login() {
const loginForm = document.getElementById('loginForm')
const user = loginForm.user.value;
const data = await getAccount(user);
if (data.error) {
return console.log('loginError', data.error);
}
account = data;
navigate('/dashboard');
}
Mai întâi, deoarece getAccount
este o funcție asincronă, trebuie să o asociem cu cuvântul cheie await
pentru a aștepta rezultatul serverului. Ca în cazul oricărei cereri către server, trebuie să gestionăm și cazurile de eroare. Deocamdată vom adăuga doar un mesaj de jurnal pentru a afișa eroarea și vom reveni la aceasta mai târziu.
Apoi trebuie să stocăm datele undeva pentru a le putea folosi ulterior pentru a afișa informațiile pe tabloul de bord. Deoarece variabila account
nu există încă, vom crea o variabilă globală pentru aceasta în partea de sus a fișierului nostru:
let account = null;
După ce datele utilizatorului sunt salvate într-o variabilă, putem naviga de la pagina de login la dashboard folosind funcția navigate()
pe care o avem deja.
În cele din urmă, trebuie să apelăm funcția noastră login
atunci când formularul de autentificare este trimis, modificând HTML-ul:
<form id="loginForm" action="javascript:login()">
Testați că totul funcționează corect înregistrând un cont nou și încercând să vă autentificați folosind același cont.
Înainte de a trece la partea următoare, putem completa și funcția register
adăugând acest cod la sfârșitul funcției:
account = result;
navigate('/dashboard');
✅ Știați că, în mod implicit, puteți apela API-uri ale serverului doar de pe același domeniu și port ca pagina web pe care o vizualizați? Acesta este un mecanism de securitate impus de browsere. Dar stați, aplicația noastră web rulează pe localhost:3000
, în timp ce API-ul serverului rulează pe localhost:5000
, de ce funcționează? Folosind o tehnică numită Cross-Origin Resource Sharing (CORS), este posibil să efectuați cereri HTTP între origini diferite dacă serverul adaugă antete speciale la răspuns, permițând excepții pentru domenii specifice.
Aflați mai multe despre API-uri urmând această lecție
Actualizarea HTML-ului pentru afișarea datelor
Acum că avem datele utilizatorului, trebuie să actualizăm HTML-ul existent pentru a le afișa. Știm deja cum să preluăm un element din DOM folosind, de exemplu, document.getElementById()
. După ce aveți un element de bază, iată câteva API-uri pe care le puteți folosi pentru a-l modifica sau pentru a adăuga elemente copil:
-
Folosind proprietatea
textContent
puteți schimba textul unui element. Rețineți că schimbarea acestei valori elimină toți copiii elementului (dacă există) și îi înlocuiește cu textul furnizat. Astfel, este și o metodă eficientă de a elimina toți copiii unui element dat atribuindu-i un șir gol''
. -
Folosind
document.createElement()
împreună cu metodaappend()
puteți crea și atașa unul sau mai multe elemente copil noi.
✅ Folosind proprietatea innerHTML
a unui element este, de asemenea, posibil să-i schimbați conținutul HTML, dar aceasta ar trebui evitată deoarece este vulnerabilă la atacuri de tip cross-site scripting (XSS).
Sarcină
Înainte de a trece la ecranul tabloului de bord, mai este un lucru pe care ar trebui să-l facem pe pagina de login. În prezent, dacă încercați să vă autentificați cu un nume de utilizator care nu există, un mesaj este afișat în consolă, dar pentru un utilizator obișnuit nu se întâmplă nimic și nu știți ce se întâmplă.
Să adăugăm un element placeholder în formularul de autentificare unde putem afișa un mesaj de eroare, dacă este necesar. Un loc bun ar fi chiar înainte de butonul de login:
...
<div id="loginError"></div>
<button>Login</button>
...
Acest element <div>
este gol, ceea ce înseamnă că nimic nu va fi afișat pe ecran până când nu adăugăm conținut în el. Îi dăm, de asemenea, un id
pentru a-l putea prelua ușor cu JavaScript.
Reveniți la fișierul app.js
și creați o nouă funcție helper updateElement
:
function updateElement(id, text) {
const element = document.getElementById(id);
element.textContent = text;
}
Aceasta este destul de simplă: dat un id de element și un text, va actualiza conținutul text al elementului DOM cu id
-ul corespunzător. Să folosim această metodă în locul mesajului de eroare anterior din funcția login
:
if (data.error) {
return updateElement('loginError', data.error);
}
Acum, dacă încercați să vă autentificați cu un cont invalid, ar trebui să vedeți ceva de genul acesta:
Acum avem un text de eroare care apare vizual, dar dacă îl încercați cu un cititor de ecran, veți observa că nu se anunță nimic. Pentru ca textul adăugat dinamic pe o pagină să fie anunțat de cititoarele de ecran, va trebui să folosească ceva numit Live Region. Aici vom folosi un tip specific de live region numit alertă:
<div id="loginError" role="alert"></div>
Implementați același comportament pentru erorile funcției register
(nu uitați să actualizați HTML-ul).
Afișarea informațiilor pe tabloul de bord
Folosind aceleași tehnici pe care tocmai le-am văzut, ne vom ocupa și de afișarea informațiilor contului pe pagina tabloului de bord.
Acesta este aspectul unui obiect cont primit de la server:
{
"user": "test",
"currency": "$",
"description": "Test account",
"balance": 75,
"transactions": [
{ "id": "1", "date": "2020-10-01", "object": "Pocket money", "amount": 50 },
{ "id": "2", "date": "2020-10-03", "object": "Book", "amount": -10 },
{ "id": "3", "date": "2020-10-04", "object": "Sandwich", "amount": -5 }
],
}
Notă: pentru a vă ușura munca, puteți folosi contul
test
preexistent, care este deja populat cu date.
Sarcină
Să începem prin a înlocui secțiunea "Balance" din HTML pentru a adăuga elemente placeholder:
<section>
Balance: <span id="balance"></span><span id="currency"></span>
</section>
Vom adăuga, de asemenea, o nouă secțiune chiar dedesubt pentru a afișa descrierea contului:
<h2 id="description"></h2>
✅ Deoarece descrierea contului funcționează ca un titlu pentru conținutul de dedesubt, este marcată semantic ca un titlu. Aflați mai multe despre cât de importantă este structura titlurilor pentru accesibilitate și analizați critic pagina pentru a determina ce altceva ar putea fi un titlu.
În continuare, vom crea o nouă funcție în app.js
pentru a completa placeholder-ul:
function updateDashboard() {
if (!account) {
return navigate('/login');
}
updateElement('description', account.description);
updateElement('balance', account.balance.toFixed(2));
updateElement('currency', account.currency);
}
Mai întâi, verificăm că avem datele contului de care avem nevoie înainte de a merge mai departe. Apoi folosim funcția updateElement()
pe care am creat-o mai devreme pentru a actualiza HTML-ul.
Pentru a face afișarea soldului mai atractivă, folosim metoda
toFixed(2)
pentru a afișa valoarea cu 2 zecimale.
Acum trebuie să apelăm funcția noastră updateDashboard()
de fiecare dată când tabloul de bord este încărcat. Dacă ați terminat deja tema lecției 1, acest lucru ar trebui să fie simplu, altfel puteți folosi următoarea implementare.
Adăugați acest cod la sfârșitul funcției updateRoute()
:
if (typeof route.init === 'function') {
route.init();
}
Și actualizați definiția rutelor cu:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: updateDashboard }
};
Cu această modificare, de fiecare dată când pagina tabloului de bord este afișată, funcția updateDashboard()
este apelată. După o autentificare, ar trebui să puteți vedea soldul contului, moneda și descrierea.
Crearea rândurilor tabelului dinamic cu șabloane HTML
În prima lecție am folosit șabloane HTML împreună cu metoda appendChild()
pentru a implementa navigarea în aplicația noastră. Șabloanele pot fi, de asemenea, mai mici și utilizate pentru a popula dinamic părți repetitive ale unei pagini.
Vom folosi o abordare similară pentru a afișa lista tranzacțiilor în tabelul HTML.
Sarcină
Adăugați un nou șablon în <body>
:
<template id="transaction">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</template>
Acest șablon reprezintă un singur rând al tabelului, cu cele 3 coloane pe care dorim să le populăm: data, obiectul și suma unei tranzacții.
Apoi, adăugați această proprietate id
elementului <tbody>
al tabelului din șablonul tabloului de bord pentru a-l găsi mai ușor folosind JavaScript:
<tbody id="transactions"></tbody>
HTML-ul nostru este gata, să trecem la codul JavaScript și să creăm o nouă funcție createTransactionRow
:
function createTransactionRow(transaction) {
const template = document.getElementById('transaction');
const transactionRow = template.content.cloneNode(true);
const tr = transactionRow.querySelector('tr');
tr.children[0].textContent = transaction.date;
tr.children[1].textContent = transaction.object;
tr.children[2].textContent = transaction.amount.toFixed(2);
return transactionRow;
}
Această funcție face exact ceea ce sugerează numele său: folosind șablonul pe care l-am creat mai devreme, creează un nou rând de tabel și completează conținutul acestuia folosind datele tranzacției. Vom folosi aceasta în funcția noastră updateDashboard()
pentru a popula tabelul:
const transactionsRows = document.createDocumentFragment();
for (const transaction of account.transactions) {
const transactionRow = createTransactionRow(transaction);
transactionsRows.appendChild(transactionRow);
}
updateElement('transactions', transactionsRows);
Aici folosim metoda document.createDocumentFragment()
care creează un nou fragment DOM pe care putem lucra, înainte de a-l atașa în final tabelului nostru HTML.
Mai este un lucru pe care trebuie să-l facem înainte ca acest cod să funcționeze, deoarece funcția noastră updateElement()
acceptă în prezent doar conținut text. Să modificăm puțin codul acesteia:
function updateElement(id, textOrNode) {
const element = document.getElementById(id);
element.textContent = ''; // Removes all children
element.append(textOrNode);
}
Folosim metoda append()
deoarece permite atașarea fie a textului, fie a nodurilor DOM unui element părinte, ceea ce este perfect pentru toate cazurile noastre de utilizare.
Dacă încercați să vă autentificați folosind contul test
, ar trebui să vedeți acum o listă de tranzacții pe tabloul de bord 🎉.
🚀 Provocare
Lucrați împreună pentru a face pagina tabloului de bord să arate ca o aplicație bancară reală. Dacă deja ați stilizat aplicația, încercați să folosiți media queries pentru a crea un design responsiv care funcționează bine atât pe dispozitive desktop, cât și pe cele mobile.
Iată un exemplu de pagină de tabloul de bord stilizată:
Quiz de după lecție
Temă
Refactorizați și comentați codul
Declinarea responsabilității:
Acest document a fost tradus folosind serviciul de traducere AI Co-op Translator. Deși depunem eforturi pentru a asigura acuratețea, vă rugăm să rețineți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa nativă ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm răspunderea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.