# Створення банківського додатку, частина 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 вашого браузера? ![Скріншот зміни 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). Хоча ми прагнемо до точності, звертаємо вашу увагу, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.