You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
17 KiB
308 lines
17 KiB
<!--
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
{
|
|
"original_hash": "f587e913e3f7c0b1c549a05dd74ee8e5",
|
|
"translation_date": "2025-08-28T03:25:32+00:00",
|
|
"source_file": "7-bank-project/3-data/README.md",
|
|
"language_code": "hu"
|
|
}
|
|
-->
|
|
# 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
|
|
|
|
[Előadás előtti kvíz](https://ff-quizzes.netlify.app/web/quiz/45)
|
|
|
|
### 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](../2-forms/README.md) részét. Továbbá telepítened kell a [Node.js](https://nodejs.org) alkalmazást, és helyileg futtatnod kell a [szerver API-t](../api/README.md), 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:
|
|
|
|
```sh
|
|
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)](https://en.wikipedia.org/wiki/Ajax_(programming)). 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](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) 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`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) volt. Azonban a modern böngészők már támogatják a kényelmesebb és erőteljesebb [`Fetch` API-t](https://developer.mozilla.org/docs/Web/API/Fetch_API), 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](https://caniuse.com/fetch).
|
|
|
|
### Feladat
|
|
|
|
Az [előző leckében](../2-forms/README.md) 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:
|
|
|
|
```js
|
|
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:
|
|
|
|
```js
|
|
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`](https://developer.mozilla.org/docs/Web/HTTP/Methods/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:
|
|
|
|
```js
|
|
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:
|
|
|
|
```js
|
|
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:
|
|
|
|
```html
|
|
<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:
|
|
|
|
```js
|
|
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)](https://developer.mozilla.org/docs/Web/HTTP/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](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon).
|
|
|
|
## 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`](https://developer.mozilla.org/docs/Web/API/Node/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()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) és az [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append) metódusok használatával új gyermekelemeket hozhatunk létre és csatolhatunk.
|
|
|
|
✅ Az [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/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)](https://developer.mozilla.org/docs/Glossary/Cross-site_scripting) 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:
|
|
|
|
```html
|
|
...
|
|
<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:
|
|
|
|
```js
|
|
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:
|
|
|
|
```js
|
|
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](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/ARIA_Live_Regions) használatára van szükség. Itt egy speciális típusú live region-t, egy figyelmeztetést (alert) fogunk használni:
|
|
|
|
```html
|
|
<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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```html
|
|
<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:
|
|
|
|
```html
|
|
<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](https://www.nomensa.com/blog/2017/how-structure-headings-web-accessibility) 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:
|
|
|
|
```js
|
|
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)`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) 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](../1-template-route/assignment.md), 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:
|
|
|
|
```js
|
|
if (typeof route.init === 'function') {
|
|
route.init();
|
|
}
|
|
```
|
|
|
|
És frissítsd az útvonalak definícióját az alábbiak szerint:
|
|
|
|
```js
|
|
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](../1-template-route/README.md) 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:
|
|
|
|
```html
|
|
<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:
|
|
|
|
```html
|
|
<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](https://developer.mozilla.org/docs/Web/CSS/Media_Queries) funkciót, hogy [reszponzív dizájnt](https://developer.mozilla.org/docs/Web/Progressive_web_apps/Responsive/responsive_design_building_blocks) 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
|
|
|
|
[Előadás utáni kvíz](https://ff-quizzes.netlify.app/web/quiz/46)
|
|
|
|
## Feladat
|
|
|
|
[Refaktoráld és kommentáld a kódodat](assignment.md)
|
|
|
|
---
|
|
|
|
**Felelősségkizárás**:
|
|
Ez a dokumentum az [Co-op Translator](https://github.com/Azure/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. |