# Створення банківського додатку, частина 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`. Чи виглядає воно інакше, ніж інші поля? Спробуйте взаємодіяти з ним. ✅ Чи можете ви навігувати та взаємодіяти з формами, використовуючи лише клавіатуру? Як би ви це зробили? ## Надсилання даних на сервер Тепер, коли у нас є функціональний інтерфейс, наступний крок — надіслати дані на сервер. Давайте швидко протестуємо наш поточний код: що відбувається, якщо ви натискаєте кнопку *Login* або *Register*? Чи помітили ви зміну в адресному рядку вашого браузера? ![Знімок екрана зі зміною URL браузера після натискання кнопки Register](../../../../translated_images/click-register.e89a30bf0d4bc9ca867dc537c4cea679a7c26368bd790969082f524fed2355bc.uk.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.uk.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. Ми використовуємо API `fetch()` для надсилання 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.uk.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.uk.png) Валідація, яка виконується *до* надсилання будь-яких даних на сервер, називається **клієнтською валідацією**. Але зверніть увагу, що не завжди можливо виконати всі перевірки без надсилання даних. Наприклад, ми не можемо перевірити тут, чи існує вже обліковий запис із таким самим ім’ям користувача, без запиту до сервера. Додаткова валідація, яка виконується на сервері, називається **серверною валідацією**. Зазвичай потрібно реалізовувати обидва типи валідації. Клієнтська валідація покращує взаємодію з користувачем, надаючи миттєвий зворотний зв’язок, але серверна валідація є критично важливою для забезпечення коректності та безпеки даних користувача. --- ## 🚀 Виклик Показуйте повідомлення про помилку в HTML, якщо користувач уже існує. Ось приклад того, як може виглядати фінальна сторінка входу після невеликого стилізування: ![Знімок екрана сторінки входу після додавання стилів CSS](../../../../translated_images/result.96ef01f607bf856aa9789078633e94a4f7664d912f235efce2657299becca483.uk.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). Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критичної інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникають внаслідок використання цього перекладу.