# Създаване на банково приложение, част 3: Методи за извличане и използване на данни ## Предварителен тест [Предварителен тест](https://ff-quizzes.netlify.app/web/quiz/45) ### Въведение В основата на всяко уеб приложение стои *данните*. Данните могат да приемат различни форми, но основната им цел винаги е да предоставят информация на потребителя. С развитието на уеб приложенията, които стават все по-интерактивни и сложни, начинът, по който потребителят достъпва и взаимодейства с информацията, се превръща в ключова част от уеб разработката. В този урок ще разгледаме как да извличаме данни от сървър асинхронно и да ги използваме за показване на информация на уеб страница, без да презареждаме HTML. ### Предпоставки Трябва да сте създали [Формата за вход и регистрация](../2-forms/README.md) като част от уеб приложението за този урок. Също така трябва да инсталирате [Node.js](https://nodejs.org) и [да стартирате API сървъра](../api/README.md) локално, за да получите данни за акаунта. Можете да тествате дали сървърът работи правилно, като изпълните тази команда в терминала: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## AJAX и извличане на данни Традиционните уеб сайтове обновяват съдържанието, когато потребителят избере линк или изпрати данни чрез форма, като презареждат цялата HTML страница. Всеки път, когато трябва да се заредят нови данни, уеб сървърът връща изцяло нова HTML страница, която трябва да бъде обработена от браузъра, прекъсвайки текущото действие на потребителя и ограничавайки взаимодействията по време на презареждането. Този работен процес се нарича *многостранично приложение* или *MPA*.  С развитието на сложни и интерактивни уеб приложения се появи нова техника, наречена [AJAX (Асинхронен JavaScript и XML)](https://en.wikipedia.org/wiki/Ajax_(programming)). Тази техника позволява на уеб приложенията да изпращат и получават данни от сървър асинхронно, използвайки JavaScript, без да се налага презареждане на HTML страницата, което води до по-бързи обновявания и по-гладки взаимодействия с потребителя. Когато нови данни се получат от сървъра, текущата HTML страница може да бъде обновена с JavaScript, използвайки [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) API. С времето този подход еволюира в това, което сега наричаме [*Едностранично приложение* или *SPA*](https://en.wikipedia.org/wiki/Single-page_application).  Когато AJAX беше въведен, единственият наличен API за асинхронно извличане на данни беше [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Но съвременните браузъри вече поддържат по-удобния и мощен [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), който използва обещания и е по-подходящ за работа с JSON данни. > Въпреки че всички съвременни браузъри поддържат `Fetch API`, ако искате вашето уеб приложение да работи на стари браузъри, винаги е добра идея първо да проверите [таблицата за съвместимост на caniuse.com](https://caniuse.com/fetch). ### Задача В [предишния урок](../2-forms/README.md) реализирахме формата за регистрация за създаване на акаунт. Сега ще добавим код за вход с вече съществуващ акаунт и извличане на неговите данни. Отворете файла `app.js` и добавете нова функция `login`: ```js async function login() { const loginForm = document.getElementById('loginForm') const user = loginForm.user.value; } ``` Тук започваме с извличане на елемента на формата чрез `getElementById()`, след което получаваме потребителското име от полето за вход с `loginForm.user.value`. Всеки контрол на формата може да бъде достъпен чрез неговото име (зададено в HTML чрез атрибута `name`) като свойство на формата. По подобен начин на това, което направихме за регистрацията, ще създадем друга функция за изпълнение на заявка към сървъра, но този път за извличане на данни за акаунта: ```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' }; } } ``` Използваме `fetch` API за асинхронно извличане на данни от сървъра, но този път не ни трябват допълнителни параметри освен URL, който да извикаме, тъй като само правим заявка за данни. По подразбиране `fetch` създава [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET) HTTP заявка, което е точно това, което ни трябва тук. ✅ `encodeURIComponent()` е функция, която избягва специални символи за URL. Какви проблеми бихме могли да имаме, ако не извикаме тази функция и използваме директно стойността на `user` в URL? Сега да обновим нашата функция `login`, за да използва `getAccount`: ```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'); } ``` Първо, тъй като `getAccount` е асинхронна функция, трябва да я съчетаем с ключовата дума `await`, за да изчакаме резултата от сървъра. Както при всяка заявка към сървъра, трябва да се справим и с грешки. Засега ще добавим само съобщение за грешка в логовете и ще се върнем към това по-късно. След това трябва да съхраним данните някъде, за да можем по-късно да ги използваме за показване на информацията на таблото. Тъй като променливата `account` все още не съществува, ще създадем глобална променлива за нея в началото на файла: ```js let account = null; ``` След като данните за потребителя са запазени в променлива, можем да преминем от страницата за вход към таблото, използвайки функцията `navigate()`, която вече имаме. Накрая, трябва да извикаме нашата функция `login`, когато формата за вход бъде изпратена, като модифицираме HTML: ```html