# 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á és hogyan lép kapcsolatba az információval, 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 a HTML-t. ### Előfeltételek 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 a tartalom frissítéséhez, amikor a felhasználó egy linkre kattint vagy adatokat küld el egy űrlapon keresztül, az egész HTML-oldalt újratöltik. Minden alkalommal, amikor új adatokra van szükség, 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* (*Multi-Page Application* vagy *MPA*) is 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 a HTML-oldalt, gyorsabb frissítéseket és gördülékenyebb felhasználói élményt biztosítva. Amikor új adatok érkeznek a szerverről, a jelenlegi HTML-oldal JavaScript segítségével frissíthető 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 azzá, amit ma [*egyetlen oldalas alkalmazásnak* (*Single-Page Application* vagy *SPA*)](https://en.wikipedia.org/wiki/Single-page_application) nevezünk.  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 implementálták a kényelmesebb és erősebb [`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 vagy elavult 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, hogy létrehozzunk egy fiókot. Most kódot fogunk hozzáadni a meglévő fiókkal történő 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 azzal kezdjük, hogy a `getElementById()` segítségével 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 ahhoz, amit a regisztrációnál tettünk, 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 más paraméterekre, mint a hívandó URL-re, 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, ami 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 szerverké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 tárolnunk az adatokat valahol, hogy később felhasználhassuk őket a műszerfal információinak megjelenítésére. 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