17 KiB
Banki alkalmazás készítése 3. rész: Adatok lekérése és felhasználása
Előadás előtti kvíz
Bevezetés
Minden webalkalmazás középpontjában az adatok állnak. Az adatok sokféle formát ölthetnek, de fő céljuk mindig az, hogy információt jelenítsenek meg a felhasználó számára. Ahogy a webalkalmazások egyre interaktívabbá és összetettebbé válnak, az, hogy a felhasználó hogyan fér hozzá az információkhoz és hogyan lép velük kapcsolatba, kulcsfontosságúvá vált a webfejlesztésben.
Ebben a leckében azt fogjuk megvizsgálni, hogyan lehet aszinkron módon adatokat lekérni egy szerverről, és ezeket az adatokat úgy megjeleníteni egy weboldalon, hogy közben ne kelljen újratölteni az oldalt.
Előfeltétel
Ehhez a leckéhez szükséges, hogy már elkészítetted a webalkalmazás Bejelentkezési és Regisztrációs űrlap részét. Továbbá telepítened kell a Node.js alkalmazást, és helyileg futtatnod kell a szerver API-t, hogy hozzáférj a fiókadatokhoz.
Ellenőrizheted, hogy a szerver megfelelően fut-e, ha a következő parancsot futtatod egy terminálban:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
AJAX és adatlekérés
A hagyományos weboldalak akkor frissítik a megjelenített tartalmat, amikor a felhasználó egy linkre kattint vagy adatokat küld be egy űrlapon keresztül, azáltal, hogy újratöltik a teljes HTML oldalt. Minden alkalommal, amikor új adatokat kell betölteni, a webszerver egy teljesen új HTML oldalt küld vissza, amelyet a böngészőnek fel kell dolgoznia, megszakítva ezzel a felhasználó aktuális tevékenységét, és korlátozva az interakciókat az újratöltés ideje alatt. Ezt a munkafolyamatot többoldalas alkalmazásnak vagy MPA-nak nevezik.
Amikor a webalkalmazások egyre összetettebbé és interaktívabbá váltak, megjelent egy új technika, az AJAX (Asynchronous JavaScript and XML). Ez a technika lehetővé teszi, hogy a webalkalmazások JavaScript segítségével aszinkron módon küldjenek és fogadjanak adatokat a szerverről, anélkül hogy újratöltenék az oldalt. Ez gyorsabb frissítéseket és gördülékenyebb felhasználói élményt eredményez. Amikor új adatok érkeznek a szervertől, a jelenlegi HTML oldalt JavaScript segítségével frissíthetjük a DOM API használatával. Idővel ez a megközelítés fejlődött, és ma már egyetlen oldalas alkalmazásnak vagy SPA-nak nevezik.
Amikor az AJAX először megjelent, az egyetlen elérhető API az aszinkron adatlekéréshez az XMLHttpRequest
volt. Azonban a modern böngészők már támogatják a kényelmesebb és erőteljesebb Fetch
API-t, amely ígéreteket használ, és jobban alkalmas JSON adatok kezelésére.
Bár minden modern böngésző támogatja a
Fetch API
-t, ha azt szeretnéd, hogy a webalkalmazásod régebbi böngészőkön is működjön, mindig érdemes először ellenőrizni a caniuse.com kompatibilitási táblázatát.
Feladat
Az előző leckében megvalósítottuk a regisztrációs űrlapot egy fiók létrehozásához. Most kódot fogunk hozzáadni a meglévő fiókkal való bejelentkezéshez és az adatok lekéréséhez. Nyisd meg az app.js
fájlt, és adj hozzá egy új login
függvényt:
async function login() {
const loginForm = document.getElementById('loginForm')
const user = loginForm.user.value;
}
Itt az getElementById()
segítségével először lekérjük az űrlap elemet, majd az loginForm.user.value
segítségével megszerezzük a felhasználónevet az input mezőből. Minden űrlapvezérlő elérhető a nevével (amelyet a HTML-ben a name
attribútummal állítunk be) az űrlap tulajdonságaként.
Hasonlóan a regisztrációhoz, létrehozunk egy másik függvényt a szerver kérés végrehajtásához, de ezúttal a fiókadatok lekérésére:
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' };
}
}
A fetch
API-t használjuk az adatok aszinkron lekérésére a szerverről, de ezúttal nincs szükségünk további paraméterekre a hívandó URL-en kívül, mivel csak adatokat kérdezünk le. Alapértelmezés szerint a fetch
egy GET
HTTP kérést hoz létre, amely pontosan az, amire itt szükségünk van.
✅ Az encodeURIComponent()
egy olyan függvény, amely speciális karaktereket kódol URL-ekhez. Milyen problémák merülhetnek fel, ha nem hívjuk meg ezt a függvényt, és közvetlenül használjuk a user
értéket az URL-ben?
Most frissítsük a login
függvényünket, hogy használja a getAccount
-ot:
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');
}
Először, mivel a getAccount
egy aszinkron függvény, az await
kulcsszóval kell párosítanunk, hogy megvárjuk a szerver eredményét. Mint minden szerver kérésnél, itt is kezelni kell a hibás eseteket. Egyelőre csak egy naplóüzenetet adunk hozzá a hiba megjelenítéséhez, és később visszatérünk rá.
Ezután el kell mentenünk az adatokat valahova, hogy később felhasználhassuk őket a műszerfal információinak megjelenítéséhez. Mivel az account
változó még nem létezik, létrehozunk egy globális változót a fájl tetején:
let account = null;
Miután a felhasználói adatokat elmentettük egy változóba, a bejelentkezési oldalról a műszerfalra navigálhatunk a már meglévő navigate()
függvény használatával.
Végül, a login
függvényünket akkor kell meghívni, amikor a bejelentkezési űrlapot elküldik, az alábbi HTML módosításával:
<form id="loginForm" action="javascript:login()">
Teszteld, hogy minden megfelelően működik-e, ha regisztrálsz egy új fiókot, majd megpróbálsz bejelentkezni ugyanazzal a fiókkal.
Mielőtt továbblépnénk a következő részre, kiegészíthetjük a register
függvényt az alábbi kóddal a függvény végén:
account = result;
navigate('/dashboard');
✅ Tudtad, hogy alapértelmezés szerint csak ugyanazon domainről és portról hívhatsz szerver API-kat, mint amelyen a megtekintett weboldal fut? Ez egy böngészők által érvényesített biztonsági mechanizmus. De várjunk csak, a webalkalmazásunk a localhost:3000
-en fut, míg a szerver API a localhost:5000
-en, akkor miért működik? A Cross-Origin Resource Sharing (CORS) nevű technika használatával lehetőség van kereszt-domain HTTP kérések végrehajtására, ha a szerver speciális fejléceket ad a válaszhoz, amelyek engedélyezik az adott domainek kivételeit.
Tudj meg többet az API-król ebben a leckében.
HTML frissítése az adatok megjelenítéséhez
Most, hogy megvannak a felhasználói adatok, frissítenünk kell a meglévő HTML-t, hogy megjelenítse azokat. Már tudjuk, hogyan lehet egy elemet lekérni a DOM-ból például a document.getElementById()
segítségével. Miután van egy alap elemünk, az alábbi API-kat használhatjuk annak módosítására vagy gyermekelemek hozzáadására:
-
A
textContent
tulajdonság használatával megváltoztathatjuk egy elem szövegét. Ne feledd, hogy ennek az értéknek a megváltoztatása eltávolítja az elem összes gyermekét (ha van), és helyettesíti a megadott szöveggel. Ezért ez egy hatékony módszer is lehet egy adott elem összes gyermekének eltávolítására, ha üres karakterláncot (''
) rendelünk hozzá. -
A
document.createElement()
és azappend()
metódusok használatával új gyermekelemeket hozhatunk létre és csatolhatunk.
✅ Az innerHTML
tulajdonság használatával egy elem HTML tartalmát is megváltoztathatjuk, de ezt kerülni kell, mivel sebezhető a cross-site scripting (XSS) támadásokkal szemben.
Feladat
Mielőtt továbblépnénk a műszerfal képernyőre, van még egy dolog, amit meg kell tennünk a bejelentkezési oldalon. Jelenleg, ha megpróbálsz bejelentkezni egy nem létező felhasználónévvel, egy üzenet jelenik meg a konzolban, de egy átlagos felhasználó számára semmi sem változik, és nem tudja, mi történik.
Adjunk hozzá egy helyőrző elemet a bejelentkezési űrlaphoz, ahol szükség esetén megjeleníthetünk egy hibaüzenetet. Egy jó hely lehet például a bejelentkezési <button>
előtt:
...
<div id="loginError"></div>
<button>Login</button>
...
Ez a <div>
elem üres, ami azt jelenti, hogy semmi sem jelenik meg a képernyőn, amíg nem adunk hozzá tartalmat. Az id
attribútumot is megadjuk, hogy könnyen lekérhessük JavaScript segítségével.
Térj vissza az app.js
fájlhoz, és hozz létre egy új segédfüggvényt updateElement
néven:
function updateElement(id, text) {
const element = document.getElementById(id);
element.textContent = text;
}
Ez a függvény egyszerű: egy elem id-jét és szövegét megadva frissíti a DOM elem szövegtartalmát a megfelelő id
alapján. Használjuk ezt a metódust a korábbi hibaüzenet helyett a login
függvényben:
if (data.error) {
return updateElement('loginError', data.error);
}
Most, ha megpróbálsz bejelentkezni egy érvénytelen fiókkal, valami ilyesmit kell látnod:
Most már van egy vizuálisan megjelenő hibaüzenetünk, de ha képernyőolvasóval próbálod, észre fogod venni, hogy semmi sem kerül bejelentésre. Ahhoz, hogy a dinamikusan hozzáadott szöveget a képernyőolvasók bejelentsék, egy úgynevezett Live Region használatára van szükség. Itt egy speciális típusú live region-t, egy figyelmeztetést (alert) fogunk használni:
<div id="loginError" role="alert"></div>
Ugyanezt a viselkedést valósítsd meg a register
függvény hibái esetén is (ne felejtsd el frissíteni a HTML-t).
Információk megjelenítése a műszerfalon
Ugyanezeket a technikákat használva gondoskodunk a fiókadatok megjelenítéséről a műszerfal oldalon.
Ez így néz ki egy szervertől kapott fiókobjektum:
{
"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 }
],
}
Megjegyzés: hogy megkönnyítsük a dolgodat, használhatod az előre feltöltött
test
fiókot, amely már tartalmaz adatokat.
Feladat
Kezdjük azzal, hogy a HTML-ben lecseréljük az "Egyenleg" szekciót helyőrző elemekre:
<section>
Balance: <span id="balance"></span><span id="currency"></span>
</section>
Hozzáadunk egy új szekciót is közvetlenül alatta, hogy megjelenítsük a fiókleírást:
<h2 id="description"></h2>
✅ Mivel a fiókleírás címként funkcionál az alatta lévő tartalomhoz, szemantikailag címsorként van megjelölve. Tudj meg többet arról, hogy a címsorok struktúrája miért fontos az akadálymentesség szempontjából, és vizsgáld meg kritikusan az oldalt, hogy meghatározd, mi más lehetne címsor.
Ezután hozzunk létre egy új függvényt az app.js
fájlban a helyőrzők kitöltéséhez:
function updateDashboard() {
if (!account) {
return navigate('/login');
}
updateElement('description', account.description);
updateElement('balance', account.balance.toFixed(2));
updateElement('currency', account.currency);
}
Először ellenőrizzük, hogy rendelkezünk-e a szükséges fiókadatokkal, mielőtt továbbmennénk. Ezután a korábban létrehozott updateElement()
függvényt használjuk a HTML frissítéséhez.
Az egyenleg megjelenítésének szebbé tételéhez a
toFixed(2)
metódust használjuk, hogy az értéket 2 tizedesjeggyel jelenítsük meg.
Most minden alkalommal, amikor a műszerfal betöltődik, meg kell hívnunk az updateDashboard()
függvényt. Ha már befejezted az 1. lecke feladatát, ez egyszerű lesz, különben használhatod az alábbi megvalósítást.
Add hozzá ezt a kódot az updateRoute()
függvény végéhez:
if (typeof route.init === 'function') {
route.init();
}
És frissítsd az útvonalak definícióját az alábbiak szerint:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: updateDashboard }
};
Ezzel a változtatással minden alkalommal, amikor a műszerfal oldal megjelenik, az updateDashboard()
függvény hívódik meg. Bejelentkezés után látnod kell a fiók egyenlegét, pénznemét és leírását.
Táblasorok dinamikus létrehozása HTML sablonokkal
Az első leckében HTML sablonokat használtunk a navigáció megvalósításához az alkalmazásunkban. A sablonok kisebbek is lehetnek, és használhatók az oldal ismétlődő részeinek dinamikus kitöltésére.
Hasonló megközelítést fogunk alkalmazni a tranzakciók listájának megjelenítésére a HTML táblázatban.
Feladat
Adj hozzá egy új sablont a HTML <body>
részéhez:
<template id="transaction">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</template>
Ez a sablon egyetlen táblasort képvisel, a tranzakció három oszlopával: dátum, tárgy és összeg.
Ezután add hozzá ezt az id
tulajdonságot a táblázat <tbody>
eleméhez a műszerfal sablonban, hogy könnyebben megtalálható legyen JavaScript segítségével:
<tbody id="transactions"></tbody>
Ha a test
fiókot használod a bejelentkezéshez, most már látnod kell a tranzakciók listáját a vezérlőpulton 🎉.
🚀 Kihívás
Dolgozzatok együtt azon, hogy a vezérlőpult oldal úgy nézzen ki, mint egy valódi banki alkalmazás. Ha már formáztátok az alkalmazást, próbáljátok meg használni a media queries funkciót, hogy reszponzív dizájnt hozzatok létre, amely jól működik mind asztali, mind mobil eszközökön.
Íme egy példa egy formázott vezérlőpult oldalra:
Előadás utáni kvíz
Feladat
Refaktoráld és kommentáld a kódodat
Felelősségkizárás:
Ez a dokumentum az Co-op Translator AI fordítási szolgáltatás segítségével készült. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Kritikus információk esetén javasolt a professzionális, emberi fordítás igénybevétele. Nem vállalunk felelősséget a fordítás használatából eredő félreértésekért vagy téves értelmezésekért.