# Изградња банкарске апликације, део 2: Израда форме за пријаву и регистрацију ## Квиз пре предавања [Квиз пре предавања](https://ff-quizzes.netlify.app/web/quiz/43) ### Увод У готово свим модерним веб апликацијама можете креирати налог како бисте имали свој приватни простор. Како више корисника може истовремено приступити веб апликацији, потребан је механизам за одвојено чување личних података сваког корисника и одабир информација које ће бити приказане. Нећемо се бавити како [сигурно управљати идентитетом корисника](https://en.wikipedia.org/wiki/Authentication), јер је то обимна тема сама по себи, али ћемо осигурати да сваки корисник може креирати један (или више) банковних рачуна у нашој апликацији. У овом делу ћемо користити HTML форме за додавање пријаве и регистрације у нашу веб апликацију. Видећемо како програмски послати податке серверској API-ју и на крају како дефинисати основна правила за валидацију корисничких уноса. ### Предуслови Потребно је да сте завршили [HTML шаблоне и рутирање](../1-template-route/README.md) веб апликације за ову лекцију. Такође је потребно да инсталирате [Node.js](https://nodejs.org) и [покренете серверски API](../api/README.md) локално како бисте могли слати податке за креирање налога. **Обратите пажњу** Имаћете два терминала која раде истовремено, како је наведено у наставку: 1. За главну банкарску апликацију коју смо изградили у лекцији [HTML шаблони и рутирање](../1-template-route/README.md) 2. За [серверски API банкарске апликације](../api/README.md) који смо управо подесили. Потребно је да оба сервера буду покренута како бисте могли пратити остатак лекције. Они слушају на различитим портовима (порт `3000` и порт `5000`), тако да би све требало да функционише без проблема. Можете тестирати да ли сервер ради исправно извршавањем ове команде у терминалу: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## Форма и контроле Елемент `
` обухвата део HTML документа где корисник може уносити и слати податке помоћу интерактивних контрола. Постоје разне корисничке интерфејс (UI) контроле које се могу користити унутар форме, а најчешће су `` и `
``` Коришћењем атрибута `value` можемо дефинисати подразумевану вредност за дати унос. Такође приметите да унос за `balance` има тип `number`. Да ли изгледа другачије од осталих уноса? Пробајте да интерагујете са њим. ✅ Можете ли навигирати и интераговати са формама користећи само тастатуру? Како бисте то урадили? ## Слање података серверу Сада када имамо функционалан UI, следећи корак је слање података серверу. Хајде да направимо брз тест користећи наш тренутни код: шта се дешава ако кликнете на дугме *Login* или *Register*? Да ли сте приметили промену у URL секцији вашег претраживача? ![Снимак екрана са променом URL-а претраживача након клика на дугме Register](../../../../translated_images/click-register.e89a30bf0d4bc9ca867dc537c4cea679a7c26368bd790969082f524fed2355bc.sr.png) Подразумевана акција за `
` је да пошаље форму тренутном серверском URL-у користећи [GET метод](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3), додајући податке форме директно у URL. Овај метод има неке недостатке: - Подаци који се шаљу су веома ограничени по величини (око 2000 карактера) - Подаци су директно видљиви у URL-у (што није добро за лозинке) - Не ради са отпремањем датотека Зато можете променити метод на [POST метод](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) који шаље податке форме серверу у телу HTTP захтева, без претходно наведених ограничења. > Иако је POST најчешће коришћен метод за слање података, [у неким специфичним сценаријима](https://www.w3.org/2001/tag/doc/whenToUseGet.html) је пожељно користити GET метод, на пример приликом имплементације поља за претрагу. ### Задатак Додајте `action` и `method` својства форми за регистрацију: ```html ``` Сада покушајте да региструјете нови налог са вашим именом. Након клика на дугме *Register* требало би да видите нешто овако: ![Прозор претраживача на адреси localhost:5000/api/accounts, приказује JSON низ са корисничким подацима](../../../../translated_images/form-post.61de4ca1b964d91a9e338416e19f218504dd0af5f762fbebabfe7ae80edf885f.sr.png) Ако све функционише како треба, сервер би требало да одговори на ваш захтев са [JSON](https://www.json.org/json-en.html) одговором који садржи податке о креираном налогу. ✅ Покушајте поново да се региструјете са истим именом. Шта се дешава? ## Слање података без освежавања странице Као што сте вероватно приметили, постоји мали проблем са приступом који смо управо користили: приликом слања форме, излазимо из наше апликације и претраживач се преусмерава на серверски URL. Трудимо се да избегнемо сва освежавања странице у нашој веб апликацији, јер правимо [једностраницу апликацију (SPA)](https://en.wikipedia.org/wiki/Single-page_application). Да бисмо послали податке форме серверу без приморавања на освежавање странице, морамо користити JavaScript код. Уместо да ставимо URL у `action` својство `` елемента, можемо користити било који JavaScript код са префиксом `javascript:` за извршавање прилагођене акције. Коришћење овога такође значи да ћете морати имплементирати неке задатке који су раније аутоматски обављани од стране претраживача: - Преузимање података форме - Конвертовање и кодирање података форме у одговарајући формат - Креирање HTTP захтева и слање серверу ### Задатак Замените `action` форме за регистрацију са: ```html ``` Отворите `app.js` и додајте нову функцију под именом `register`: ```js function register() { const registerForm = document.getElementById('registerForm'); const formData = new FormData(registerForm); const data = Object.fromEntries(formData); const jsonData = JSON.stringify(data); } ``` Овде преузимамо елемент форме користећи `getElementById()` и користимо [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData) помоћни алат за екстракцију вредности из контрола форме као скуп парова кључ/вредност. Затим конвертујемо податке у регуларни објекат користећи [`Object.fromEntries()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) и на крају серијализујемо податке у [JSON](https://www.json.org/json-en.html), формат који се често користи за размену података на вебу. Подаци су сада спремни за слање серверу. Креирајте нову функцију под именом `createAccount`: ```js async function createAccount(account) { try { const response = await fetch('//localhost:5000/api/accounts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: account }); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` Шта ради ова функција? Прво, приметите `async` кључну реч овде. То значи да функција садржи код који ће се извршавати [**асинхроно**](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function). Када се користи заједно са `await` кључном речи, омогућава чекање на извршење асинхроног кода - као што је чекање на одговор сервера овде - пре наставка. Ево кратког видеа о коришћењу `async/await`: [![Async и Await за управљање промисима](https://img.youtube.com/vi/YwmlRkrxvkk/0.jpg)](https://youtube.com/watch?v=YwmlRkrxvkk "Async и Await за управљање промисима") > 🎥 Кликните на слику изнад за видео о async/await. Користимо `fetch()` API за слање JSON података серверу. Овај метод узима 2 параметра: - URL сервера, тако да овде враћамо `//localhost:5000/api/accounts`. - Подешавања захтева. Ту постављамо метод на `POST` и обезбеђујемо `body` за захтев. Како шаљемо JSON податке серверу, такође морамо поставити `Content-Type` хедер на `application/json` како би сервер знао како да интерпретира садржај. Како ће сервер одговорити на захтев са JSON-ом, можемо користити `await response.json()` за парсирање JSON садржаја и враћање резултујућег објекта. Имајте на уму да је овај метод асинхрон, па користимо `await` кључну реч овде пре враћања како бисмо били сигурни да су све грешке током парсирања такође ухваћене. Сада додајте мало кода у функцију `register` како бисте позвали `createAccount()`: ```js const result = await createAccount(jsonData); ``` Како користимо `await` кључну реч овде, потребно је додати `async` кључну реч пре функције register: ```js async function register() { ``` На крају, додајмо неке логове како бисмо проверили резултат. Коначна функција би требало да изгледа овако: ```js async function register() { const registerForm = document.getElementById('registerForm'); const formData = new FormData(registerForm); const jsonData = JSON.stringify(Object.fromEntries(formData)); const result = await createAccount(jsonData); if (result.error) { return console.log('An error occurred:', result.error); } console.log('Account created!', result); } ``` То је било мало дуго, али смо успели! Ако отворите [алатке за програмере претраживача](https://developer.mozilla.org/docs/Learn/Common_questions/What_are_browser_developer_tools) и покушате да региструјете нови налог, не би требало да видите никакву промену на веб страници, али ће се у конзоли појавити порука која потврђује да све функционише. ![Снимак екрана који приказује поруку у конзоли претраживача](../../../../translated_images/browser-console.efaf0b51aaaf67782a29e1a0bb32cc063f189b18e894eb5926e02f1abe864ec2.sr.png) ✅ Да ли мислите да се подаци шаљу серверу безбедно? Шта ако неко успе да пресретне захтев? Можете прочитати о [HTTPS](https://en.wikipedia.org/wiki/HTTPS) како бисте сазнали више о сигурној комуникацији података. ## Валидација података Ако покушате да региструјете нови налог без претходног уноса корисничког имена, можете видети да сервер враћа грешку са статусним кодом [400 (Bad Request)](https://developer.mozilla.org/docs/Web/HTTP/Status/400#:~:text=The%20HyperText%20Transfer%20Protocol%20(HTTP,%2C%20or%20deceptive%20request%20routing).). Пре слања података серверу добра је пракса [валидирати податке форме](https://developer.mozilla.org/docs/Learn/Forms/Form_validation) унапред када је то могуће, како бисте били сигурни да шаљете важећи захтев. HTML5 контроле форме пружају уграђену валидацију користећи различите атрибуте: - `required`: поље мора бити попуњено, иначе форма не може бити послата. - `minlength` и `maxlength`: дефинишу минималан и максималан број карактера у текстуалним пољима. - `min` и `max`: дефинишу минималну и максималну вредност нумеричког поља. - `type`: дефинише врсту очекиваних података, као што су `number`, `email`, `file` или [други уграђени типови](https://developer.mozilla.org/docs/Web/HTML/Element/input). Овај атрибут такође може променити визуелни приказ контроле форме. - `pattern`: омогућава дефинисање [регуларног израза](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Regular_Expressions) за проверу да ли су унети подаци валидни или не. > Савет: можете прилагодити изглед контролних елемената вашег обрасца у зависности од тога да ли су валидни или не, користећи CSS псеудо-класе `:valid` и `:invalid`. ### Задатак Постоје два обавезна поља за креирање важећег новог налога: корисничко име и валута, док су остала поља опционална. Ажурирајте HTML форме, користећи и `required` атрибут и текст у називу поља тако да: ```html ... ``` Иако ова конкретна серверска имплементација не намеће специфична ограничења за максималну дужину поља, увек је добра пракса да се дефинишу разумна ограничења за било који унос текста од стране корисника. Додајте `maxlength` атрибут текстуалним пољима: ```html ... ... ``` Сада, ако притиснете дугме *Региструј се* и неко поље не поштује правило валидације које смо дефинисали, требало би да видите нешто овако: ![Снимак екрана који приказује грешку валидације приликом покушаја слања форме](../../../../translated_images/validation-error.8bd23e98d416c22f80076d04829a4bb718e0e550fd622862ef59008ccf0d5dce.sr.png) Валидација која се обавља *пре* слања било каквих података серверу назива се **валидација на страни клијента**. Али имајте на уму да није увек могуће обавити све провере без слања података. На пример, овде не можемо проверити да ли већ постоји налог са истим корисничким именом без слања захтева серверу. Додатна валидација која се обавља на серверу назива се **валидација на страни сервера**. Обично је потребно имплементирати обе врсте валидације, и док валидација на страни клијента побољшава корисничко искуство пружањем тренутних повратних информација кориснику, валидација на страни сервера је кључна за осигурање да су подаци корисника које обрађујете исправни и безбедни. --- ## 🚀 Изазов Прикажите поруку о грешци у HTML-у ако корисник већ постоји. Ево примера како може изгледати коначна страница за пријаву након мало стилизовања: ![Снимак екрана странице за пријаву након додавања CSS стилова](../../../../translated_images/result.96ef01f607bf856aa9789078633e94a4f7664d912f235efce2657299becca483.sr.png) ## Квиз након предавања [Квиз након предавања](https://ff-quizzes.netlify.app/web/quiz/44) ## Преглед и самостално учење Програмери су постали веома креативни у својим напорима за креирање форми, посебно када је реч о стратегијама валидације. Сазнајте више о различитим токовима форми прегледајући [CodePen](https://codepen.com); можете ли пронаћи неке занимљиве и инспиративне форме? ## Задатак [Стилизујте своју апликацију за банкарство](assignment.md) --- **Одрицање од одговорности**: Овај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако настојимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не сносимо одговорност за било каква неспоразумевања или погрешна тумачења која могу произаћи из коришћења овог превода.