mirror of
https://github.com/microsoft/Web-Dev-For-Beginners.git
synced 2025-08-30 18:10:10 +02:00
folder names
This commit is contained in:
17
7-bank-project/2-forms/.github/post-lecture-quiz.md
vendored
Normal file
17
7-bank-project/2-forms/.github/post-lecture-quiz.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
*Complete this quiz by checking one answer per question.*
|
||||
|
||||
1. Using `<label>` elements in forms is only for making the form pretty
|
||||
|
||||
- [ ] true
|
||||
- [ ] false
|
||||
|
||||
2. How can you define how a form is sent to the server?
|
||||
|
||||
- [ ] using the `action` attribute
|
||||
- [ ] using the `method` attribute
|
||||
- [ ] both
|
||||
|
||||
3. Which attribute can you use to set the maximum size of a text `<input>`?
|
||||
- [ ] `max`
|
||||
- [ ] `maxlength`
|
||||
- [ ] `pattern`
|
16
7-bank-project/2-forms/.github/pre-lecture-quiz.md
vendored
Normal file
16
7-bank-project/2-forms/.github/pre-lecture-quiz.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
*Complete this quiz in class.*
|
||||
|
||||
1. HTML forms allow to send user input to a server without using JavaScript
|
||||
|
||||
- [ ] true
|
||||
- [ ] false
|
||||
|
||||
2. `<label>` elements are mandatory for every form control
|
||||
|
||||
- [ ] true
|
||||
- [ ] false
|
||||
|
||||
3. It is secure to send form data to a server over HTTP
|
||||
|
||||
- [ ] true
|
||||
- [ ] false
|
286
7-bank-project/2-forms/README.md
Normal file
286
7-bank-project/2-forms/README.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Build a Login and Registration Form
|
||||
|
||||
## [Pre-lecture quiz](.github/pre-lecture-quiz.md)
|
||||
|
||||
### Introduction
|
||||
|
||||
In almost all modern web apps, you can create an account to have your own private space. As multiple users can access a web app at the same time, you need a mechanism to store each user personal data separately and select which information to display information. We won't cover how to manage [user identity securely](https://en.wikipedia.org/wiki/Authentication) as it's an extensive topic on its own, but we'll make sure each user is able to create one (or more) bank account on our app.
|
||||
|
||||
In this part we'll use HTML forms to add login and registration to our web app. We'll see how to send the data to a server API programmatically, and ultimately how to define basic validation rules for user inputs.
|
||||
|
||||
### Prerequisite
|
||||
|
||||
You need to have completed the [HTML templates and routing](../1-template-route/README.md) of the web app for this lesson. You also need to install [Node.js](https://nodejs.org) and [run the server API](../api/README.md) locally so you can send data to create accounts.
|
||||
|
||||
You can test that the server is running properly by executing this command in a terminal:
|
||||
|
||||
```sh
|
||||
curl http://localhost:5000/api
|
||||
# -> should return "Bank API v1.0.0" as a result
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Form and controls
|
||||
|
||||
The `<form>` element encapsulates a section of an HTML document where the user can input and submit data with interactive controls. There are all sorts of user interface (UI) controls that can be used within a form, the most common one being the `<input>` and the `<button>` elements.
|
||||
|
||||
There are a lot of different [types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) of `<input>`, for example to create a field where the user can enter its username you can use:
|
||||
|
||||
```html
|
||||
<input name="username" type="text">
|
||||
```
|
||||
|
||||
The `name` attribute is used to identify the control and will be used as the property name when the form data will be sent over.
|
||||
|
||||
> Take a look at the whole list of [`<input>` types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) and [other form controls](https://developer.mozilla.org/en-US/docs/Learn/Forms/Other_form_controls) to get an idea of all the native UI elements you can use when building your UI.
|
||||
|
||||
✅ Note that `<input>` is an [empty element](https://developer.mozilla.org/en-US/docs/Glossary/Empty_element) on which you should *not* add a matching closing tag. You can however use the self-closing `<input/>` notation, but it's not required.
|
||||
|
||||
The `<button>` element within a form is a bit special. If you do not specify its `type` attribute, it will automatically submit the form data to the server when pressed. Here are the possible `type` values:
|
||||
|
||||
- `submit`: The default within a `<form>`, the button triggers the form submit action.
|
||||
- `reset`: The button resets all the form controls to their initial values.
|
||||
- `button`: Do not assign a default behavior when the button is pressed. You can then assign custom actions to it using JavaScript.
|
||||
|
||||
### Task:
|
||||
|
||||
Let's start by adding a form to the `login` template. We'll need a *username* field and a *Login* button.
|
||||
|
||||
```html
|
||||
<template id="login">
|
||||
<h1>Bank App</h1>
|
||||
<section>
|
||||
<h2>Login</h2>
|
||||
<form id="loginForm">
|
||||
<label for="user">Username</label>
|
||||
<input name="user" type="text">
|
||||
<button>Login</button>
|
||||
</form>
|
||||
</section>
|
||||
</template>
|
||||
```
|
||||
|
||||
If you take a closer look, you can notice that we also added a `<label>` element here. `<label>` are used to add a caption for UI controls, such as our username field. Labels are important for the readbility of your forms, but also comes with additional benefits:
|
||||
|
||||
- By associating a label to a form control, it helps users using assistive technologies (like a screen reader) to understand what data they're expected to provide.
|
||||
- You can click on the label to directly put focus on the associated input, making it easier to reach on touch-screen based devices.
|
||||
|
||||
> [Accessibility](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility) on the web is a very important topic that's often overlooked. Thanks to [HTML5 semantic elements](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML) it's not difficult to create accessible content if you use them properly. You can [read more about accessibility](https://developer.mozilla.org/en-US/docs/Web/Accessibility) to avoid common mistakes and become a responsible developer.
|
||||
|
||||
Now we'll add a second form for the registration, just below the previous one:
|
||||
|
||||
```html
|
||||
<hr/>
|
||||
<h2>Register</h2>
|
||||
<form id="registerForm">
|
||||
<label for="user">Username</label>
|
||||
<input name="user" type="text">
|
||||
<label for="currency">Currency</label>
|
||||
<input name="currency" type="text" value="$">
|
||||
<label for="description">Description</label>
|
||||
<input name="description" type="text">
|
||||
<label for="balance">Current balance</label>
|
||||
<input name="balance" type="number" value="0">
|
||||
<button>Register</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
Using the `value` attribute we can define a default value for a given input.
|
||||
Notice also that the input for `balance` has the `number` type. Does it look different than the other inputs? Try interacting with it.
|
||||
|
||||
✅ Can you navigate and interact with the forms using only a keyboard? How would you do that?
|
||||
|
||||
## Submitting data to the server
|
||||
|
||||
Now that we have a functional UI, the next step is to send the data over to our server. Let's make a quick test using our current code: what happens if you click on the *Login* or *Register* button?
|
||||
|
||||
Did you notice the change in your browser's URL section?
|
||||
|
||||

|
||||
|
||||
The default action for a `<form>` is to submit the form to the current server URL using the [GET method](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3), appending the form data directly to the URL. This method has some shortcomings though:
|
||||
|
||||
- The data sent is very limited in size (about 2000 characters)
|
||||
- The data is directly visible in the URL (not great for passwords)
|
||||
- It does not work with file uploads
|
||||
|
||||
That's why you can change it to use the [POST method](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) which sends the form data to the server in the body of the HTTP request, without any of the previous limitations.
|
||||
|
||||
> While POST is the most commonly used method to send data over, [in some specific scenarios](https://www.w3.org/2001/tag/doc/whenToUseGet.html) it is preferable to use the GET method, when implementing a search field for example.
|
||||
|
||||
### Task
|
||||
|
||||
Add `action` and `method` properties to the registration form:
|
||||
|
||||
```html
|
||||
<form id="registerForm" action="//localhost:5000/api/accounts" method="POST">
|
||||
```
|
||||
|
||||
Now try to register a new account with your name. After clicking on the *Register* button you should see something like this:
|
||||
|
||||

|
||||
|
||||
If everything goes well, the server should answer your request with a [JSON](https://www.json.org/json-en.html) response containing the account data that was created.
|
||||
|
||||
✅ Try registering again with the same name. What happens?
|
||||
|
||||
## Submitting data without reloading the page
|
||||
|
||||
As you probably noticed, there's a slight issue with the approach we just used: when submitting the form, we get out of our app and the browser redirects to the server URL. We're trying to avoid all page reloads with our web app, as we're makng a [Single-page application (SPA)](https://en.wikipedia.org/wiki/Single-page_application).
|
||||
|
||||
To send the form data to the server without forcing a page reload, we have to use JavaScript code. Instead of putting an URL in the `action` property of a `<form>` element, you can use any JavaScript code prepended by the `javascript:` string to perform a custom action. Using this also means that you'll have to implement some tasks that were previously done automatically by the browser:
|
||||
|
||||
- Retrieve the form data
|
||||
- Convert and encode the form data to a suitable format
|
||||
- Create the HTTP request and send it to the server
|
||||
|
||||
### Task
|
||||
|
||||
Replace the registration form `action` with:
|
||||
|
||||
```html
|
||||
<form id="registerForm" action="javascript:register()">
|
||||
```
|
||||
|
||||
Open `app.js` add a new function named `register`:
|
||||
|
||||
```js
|
||||
function register() {
|
||||
const registerForm = document.getElementById('registerForm');
|
||||
const formData = new FormData(registerForm);
|
||||
const data = Object.fromEntries(formData);
|
||||
const jsonData = JSON.stringify(data);
|
||||
}
|
||||
```
|
||||
|
||||
Here we retrieve the form element using `getElementById()` and use the [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) helper to extract the values from form controls as a set of key/value pairs. Then we convert the data to a regular object using [`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) and finally serialize the data to [JSON](https://www.json.org/json-en.html), a format commonly used for exchanging data on the web.
|
||||
|
||||
The data is now ready to be sent to the server. Create a new function named `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' };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
What's this function doing? First, notice the `async` keyword here. This means that the function contains code that will execute [**asynchronously**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function). When used along the `await` keyword, it allows waiting for asynchronous code to execute - like waiting for the server response here - before continuing.
|
||||
|
||||
Here's a quick video about `async/await` usage:
|
||||
|
||||
[](https://youtube.com/watch?v=YwmlRkrxvkk "Async and Await for managing promises")
|
||||
|
||||
We use the `fetch()` API to send JSON data to the server. This method takes 2 parameters:
|
||||
|
||||
- The URL of the server, so we put back `//localhost:5000/api/accounts` here.
|
||||
- The settings of the request. That's where we set the method to `POST` and provide the `body` for the request. As we're sending JSON data to the server, we also need to set the `Content-Type` header to `application/json` so the server know how to interpret the content.
|
||||
|
||||
As the server will respond to the request with JSON, we can use `await response.json()` to parse the JSON content and return the resulting object. Note that this method is asynchronous, so we use the `await` keyword here before returning to make sure any errors during parsing are also caught.
|
||||
|
||||
Now add some code to the `register` function to call `createAccount()`:
|
||||
|
||||
```js
|
||||
const result = await createAccount(jsonData);
|
||||
```
|
||||
|
||||
Because we use the `await` keyword here, we need to add the `async` keyword before the register function:
|
||||
|
||||
```js
|
||||
async function register() {
|
||||
```
|
||||
|
||||
Finally, let's add some logs to check the result. The final function should look like this:
|
||||
|
||||
```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 occured:', result.error);
|
||||
}
|
||||
|
||||
console.log('Account created!', result);
|
||||
}
|
||||
```
|
||||
|
||||
That was a bit long but we got there! If you open your [browser developer tools](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools), and try registering a new account, you should not see any change on the web page but a message will appear in the console confirming that everything works.
|
||||
|
||||

|
||||
|
||||
✅ Do you think the data is sent to the server securely? What if someone what was able to intercept the request? You can read about [HTTPS](https://en.wikipedia.org/wiki/HTTPS) to know more about secure data communication.
|
||||
|
||||
## Data validation
|
||||
|
||||
If you try to register a new account without setting an username first, you can see that the server returns an error with status code [400 (Bad Request)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400#:~:text=The%20HyperText%20Transfer%20Protocol%20(HTTP,%2C%20or%20deceptive%20request%20routing).).
|
||||
|
||||
Before sending data to a server it's a good practice to [validate the form data](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation) beforehand when possible, to make sure you send a valid request. HTML5 forms controls provides built-in validation using various attributes:
|
||||
|
||||
- `required`: the field needs to be filled otherwise the form cannot be submitted.
|
||||
- `minlength` and `maxlength`: defines the minimum and maximum number of characters in text fields.
|
||||
- `min` and `max`: defines the minimum and maximum value of a numerical field.
|
||||
- `type`: defines the kind of data expected, like `number`, `email`, `file` or [other built-in types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). This attribute may also change the visual rendering of the form control.
|
||||
- `pattern`: allows to define a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) pattern to test if the entered data is valid or not.
|
||||
|
||||
> Tip: you can customize the look of your form controls depending if they're valid or not using the `:valid` and `:invalid` CSS pseudo-classes.
|
||||
|
||||
### Task
|
||||
|
||||
There are 2 required fields to create a valid new account, the username and currency, the other fields being optional. Update the form in the HTML to reflect that:
|
||||
|
||||
```html
|
||||
<input name="user" type="text" required>
|
||||
...
|
||||
<input name="currency" type="text" value="$" required>
|
||||
```
|
||||
|
||||
While this particular server implementation does not enforce specific limits on the fields maximum length, it's always a good practice to define reasonable limits for any user text entry.
|
||||
|
||||
Add a `maxlength` attribute to the text fields:
|
||||
|
||||
```html
|
||||
<input name="user" type="text" maxlength="20" required>
|
||||
...
|
||||
<input name="currency" type="text" value="$" maxlength="5" required>
|
||||
...
|
||||
<input name="description" type="text" maxlength="100">
|
||||
```
|
||||
|
||||
Now if you press the *Register* button and a field does not respect a validation rule we defined, you should see something like this:
|
||||
|
||||

|
||||
|
||||
Validation like this performed *before* sending any data to the server is called **client-side** validation. But note that's it's not always possible to peform all checks without sending the data. For example, we cannot check here if an account already exists with the same username without sending a request to the server. Additional validation performed on the server is called **server-side** validation.
|
||||
|
||||
Usually both need to be implemented, and while using client-side validation improves the user experience by providing instant feedback to the user, server-side validation is crucial to make sure the user data you manipulate is sound and safe.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
Show an error message in the HTML if the user already exists.
|
||||
|
||||
Here's an example of what the final login page can look like after a bit of styling:
|
||||
|
||||

|
||||
|
||||
## [Post-lecture quiz](.github/post-lecture-quiz.md)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
Developers have gotten very creative about their form building efforts, especially regarding validation strategies. Learn about different form flows by looking through [CodePen](https://codepen.com); can you find some interesting and inspiring forms?
|
||||
|
||||
## Assignment
|
||||
|
||||
[Style your bank app](assignment.md)
|
13
7-bank-project/2-forms/assignment.md
Normal file
13
7-bank-project/2-forms/assignment.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Style your bank app
|
||||
|
||||
## Instructions
|
||||
|
||||
Create a new `styles.css` file and add a link to it in your current `index.html` file. In the CSS file you just created add some styling to make the *Login* and *Dashboard* page looks nice and tidy. Try to create a color theme to give your app its own branding.
|
||||
|
||||
> Tip: you can modify the HTML and add new elements and classes if needed.
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
|
||||
| | All pages looks clean and readable, with a consistent color theme and and the different sections standing out properly. | Pages are styled but without a theme or with sections not clearly delimitated. | Pages lack styling, the sections looks disorganized and the information is difficult to read. |
|
BIN
7-bank-project/2-forms/images/browser-console.png
Normal file
BIN
7-bank-project/2-forms/images/browser-console.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
7-bank-project/2-forms/images/click-register.png
Normal file
BIN
7-bank-project/2-forms/images/click-register.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
7-bank-project/2-forms/images/form-post.png
Normal file
BIN
7-bank-project/2-forms/images/form-post.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
7-bank-project/2-forms/images/result.png
Normal file
BIN
7-bank-project/2-forms/images/result.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
BIN
7-bank-project/2-forms/images/validation-error.png
Normal file
BIN
7-bank-project/2-forms/images/validation-error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
291
7-bank-project/2-forms/translation/README.es.md
Normal file
291
7-bank-project/2-forms/translation/README.es.md
Normal file
@@ -0,0 +1,291 @@
|
||||
# Cree un formulario de inicio de sesión y registro
|
||||
|
||||
## [Prueba previa a la conferencia](.github/prelecture-quiz.md)
|
||||
|
||||
### Introducción
|
||||
|
||||
En casi todas las aplicaciones web modernas, puede crear una cuenta para tener su propio espacio privado. Como varios usuarios pueden acceder a una aplicación web al mismo tiempo, necesita un mecanismo para almacenar los datos personales de cada usuario por separado y seleccionar qué información mostrar. No cubriremos cómo administrar [la identidad del usuario de forma segura](https://en.wikipedia.org/wiki/Authentication) ya que es un tema extenso en sí mismo, pero nos aseguraremos de que cada usuario pueda crear uno. O más cuenta bancaria en nuestra aplicación.
|
||||
|
||||
En esta parte usaremos formularios HTML para agregar inicio de sesión y registro a nuestra aplicación web. Veremos cómo enviar los datos a una API de servidor de forma programática y, en última instancia, cómo definir reglas de validación básicas para las entradas del usuario.
|
||||
|
||||
### Requisito previo
|
||||
|
||||
Debe haber completado las [plantillas HTML y enrutamiento](../1-template-route/README.md) de la aplicación web para esta lección. También necesita instalar [Node.js](https://nodejs.org) y [ejecutar la API del servidor](../api/README.md) localmente para poder enviar datos para crear cuentas.
|
||||
|
||||
Puede probar que el servidor está funcionando correctamente ejecutando este comando en una terminal:
|
||||
|
||||
```sh
|
||||
curl http://localhost:5000/api
|
||||
# -> should return "Bank API v1.0.0" as a result
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Forma y controles
|
||||
|
||||
El elemento `<form>` encapsula una sección de un documento HTML donde el usuario puede ingresar y enviar datos con controles interactivos. Hay todo tipo de controles de interfaz de usuario (UI) que se pueden usar dentro de un formulario, siendo el más común los elementos `<input>` y `<button>`.
|
||||
|
||||
Hay muchos [types diferentes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) de `<input>`, por ejemplo, para crear un campo donde el usuario puede ingresar su nombre de usuario que puede usar:
|
||||
|
||||
|
||||
```html
|
||||
<input name="username" type="text">
|
||||
```
|
||||
|
||||
El atributo `name` se usa para identificar el control y se usará como el nombre de la propiedad cuando se envíen los datos del formulario.
|
||||
|
||||
> Eche un vistazo a la lista completa de [`<input>` tipos](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) y [otros controles de formulario](https://developer.mozilla.org/en-US/docs/Learn/Forms/Other_form_controls) para tener una idea de todos los elementos nativos de la interfaz de usuario que puede utilizar al crear su interfaz de usuario.
|
||||
|
||||
✅ Tenga en cuenta que `<input>` es un [elemento vacío](https://developer.mozilla.org/en-US/docs/Glossary/Empty_element) en el que *no* debe agregar una etiqueta de cierre coincidente. Sin embargo, puede usar la notación de cierre automático `<input/>`, pero no es necesaria.
|
||||
|
||||
El elemento `<button>` dentro de un formulario es un poco especial. Si no especifica su atributo `type`, automáticamente enviará los datos del formulario al servidor cuando se presione. Estos son los posibles valores de tipo:
|
||||
|
||||
- `enviar`: el valor predeterminado dentro de un` <formulario> `, el botón activa la acción de envío del formulario.
|
||||
- `reset`: El botón restablece todos los controles de formulario a sus valores iniciales.
|
||||
- `button`: No asigna un comportamiento predeterminado cuando se presiona el botón. A continuación, puede asignarle acciones personalizadas mediante JavaScript.
|
||||
|
||||
### Tarea:
|
||||
|
||||
Comencemos agregando un formulario a la plantilla de inicio de sesión. Necesitaremos un campo *nombre de usuario* y un botón *Iniciar sesión*.
|
||||
|
||||
|
||||
```html
|
||||
<template id="login">
|
||||
<h1>Bank App</h1>
|
||||
<section>
|
||||
<h2>Login</h2>
|
||||
<form id="loginForm">
|
||||
<label for="user">Username</label>
|
||||
<input name="user" type="text">
|
||||
<button>Login</button>
|
||||
</form>
|
||||
</section>
|
||||
</template>
|
||||
```
|
||||
|
||||
Si observa más de cerca, puede notar que también agregamos un elemento `<label>` aquí. Las `<label>` se utilizan para agregar un título para los controles de la IU, como nuestro campo de nombre de usuario. Las etiquetas son importantes para la legibilidad de sus formularios, pero también tienen beneficios adicionales:
|
||||
|
||||
- Al asociar una etiqueta a un control de formulario, ayuda a los usuarios que utilizan tecnologías de asistencia (como un lector de pantalla) a comprender qué datos se espera que proporcionen.
|
||||
- Puede hacer clic en la etiqueta para centrarse directamente en la entrada asociada, lo que facilita el acceso a los dispositivos con pantalla táctil.
|
||||
|
||||
> [Accesibilidad](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility) en la web es un tema muy importante que a menudo se pasa por alto. Gracias a los [elementos semánticos HTML5](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML) no es difícil crear contenido accesible si los usas correctamente. Puede [leer más sobre accesibilidad](https://developer.mozilla.org/en-US/docs/Web/Accessibility) para evitar errores comunes y convertirse en un desarrollador responsable.
|
||||
|
||||
Ahora agregaremos un segundo formulario para el registro, justo debajo del anterior:
|
||||
|
||||
|
||||
```html
|
||||
<hr/>
|
||||
<h2>Register</h2>
|
||||
<form id="registerForm">
|
||||
<label for="user">Username</label>
|
||||
<input name="user" type="text">
|
||||
<label for="currency">Currency</label>
|
||||
<input name="currency" type="text" value="$">
|
||||
<label for="description">Description</label>
|
||||
<input name="description" type="text">
|
||||
<label for="balance">Current balance</label>
|
||||
<input name="balance" type="number" value="0">
|
||||
<button>Register</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
Usando el atributo `value` podemos definir un valor predeterminado para una entrada dada.
|
||||
Observe también que la entrada para `balance` tiene el tipo `number`. ¿Se ve diferente a las otras entradas? Intenta interactuar con él.
|
||||
|
||||
✅ ¿Puede navegar e interactuar con los formularios usando solo un teclado? ¿Cómo lo harías tú?
|
||||
|
||||
## Envío de datos al servidor
|
||||
|
||||
Ahora que tenemos una interfaz de usuario funcional, el siguiente paso es enviar los datos a nuestro servidor. Hagamos una prueba rápida con nuestro código actual: ¿qué sucede si hace clic en el botón *Iniciar sesión* o *Registrarse*?
|
||||
|
||||
¿Notó el cambio en la sección de URL de su navegador?
|
||||
|
||||
! [Captura de pantalla del cambio de URL del navegador después de hacer clic en el botón Registrar](./images/click-register.png)
|
||||
|
||||
La acción predeterminada para un `<form>` es enviar el formulario a la URL del servidor actual utilizando el [método GET](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3 ), agregando los datos del formulario directamente a la URL. Sin embargo, este método tiene algunas deficiencias:
|
||||
|
||||
- Los datos enviados son de tamaño muy limitado (unos 2000 caracteres)
|
||||
- Los datos son directamente visibles en la URL (no es ideal para contraseñas)
|
||||
- No funciona con cargas de archivos.
|
||||
|
||||
Es por eso que puede cambiarlo para usar el [método POST](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) que envía los datos del formulario al servidor en el cuerpo de la solicitud HTTP, sin ninguna de las limitaciones anteriores.
|
||||
|
||||
> Si bien POST es el método más utilizado para enviar datos, [en algunos escenarios específicos](https://www.w3.org/2001/tag/doc/whenToUseGet.html) es preferible utilizar el método GET, al implementar un campo de búsqueda, por ejemplo.
|
||||
|
||||
### Tarea
|
||||
|
||||
Agregue las propiedades `action` y `method` al formulario de registro:
|
||||
|
||||
```html
|
||||
<form id="registerForm" action="//localhost:5000/api/accounts" method="POST">
|
||||
```
|
||||
|
||||
Ahora intente registrar una nueva cuenta con su nombre. Después de hacer clic en el botón * Registrarse *, debería ver algo como esto:
|
||||
|
||||

|
||||
|
||||
Si todo va bien, el servidor debe responder a su solicitud con una respuesta [JSON](https://www.json.org/json-en.html) que contenga los datos de la cuenta que se creó.
|
||||
|
||||
✅ Intente registrarse nuevamente con el mismo nombre. ¿Lo que pasa?
|
||||
|
||||
## Envío de datos sin recargar la página
|
||||
|
||||
Como probablemente haya notado, hay un pequeño problema con el enfoque que acabamos de usar: al enviar el formulario, salimos de nuestra aplicación y el navegador redirige a la URL del servidor. Estamos tratando de evitar todas las recargas de páginas con nuestra aplicación web, ya que estamos creando una [Aplicación de una sola página (SPA)](https://en.wikipedia.org/wiki/Single-page_application).
|
||||
|
||||
Para enviar los datos del formulario al servidor sin forzar la recarga de una página, tenemos que usar código JavaScript. En lugar de poner una URL en la propiedad `action` de un elemento `<form>`, puede usar cualquier código JavaScript precedido por la cadena `javascript:` para realizar una acción personalizada. Usar esto también significa que tendrá que implementar algunas tareas que anteriormente el navegador realizaba automáticamente:
|
||||
|
||||
- Recuperar los datos del formulario
|
||||
- Convierta y codifique los datos del formulario a un formato adecuado
|
||||
- Crea la solicitud HTTP y envíala al servidor
|
||||
|
||||
### Tarea
|
||||
|
||||
Reemplace el formulario de registro `acción` con:
|
||||
|
||||
```html
|
||||
<form id="registerForm" action="javascript:register()">
|
||||
```
|
||||
|
||||
Abra `app.js` agregue una nueva función llamada `registro`:
|
||||
|
||||
```js
|
||||
function register() {
|
||||
const registerForm = document.getElementById('registerForm');
|
||||
const formData = new FormData(registerForm);
|
||||
const data = Object.fromEntries(formData);
|
||||
const jsonData = JSON.stringify(data);
|
||||
}
|
||||
```
|
||||
|
||||
Aquí recuperamos el elemento del formulario usando `getElementById()` y usamos el ayudante [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) para extraer los valores del formulario controles como un conjunto de pares clave/valor. Luego convertimos los datos a un objeto regular usando [`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) y finalmente serialice los datos en [JSON](https://www.json.org/json-en.html), un formato que se utiliza comúnmente para intercambiar datos en la web.
|
||||
|
||||
Los datos ahora están listos para enviarse al servidor. Cree una nueva función llamada `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' };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
¿Qué hace esta función? Primero, observe la palabra clave `async` aquí. Esto significa que la función contiene código que se ejecutará [** asincrónicamente**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function). Cuando se usa junto con la palabra clave `await`, permite esperar a que se ejecute el código asincrónico, como esperar la respuesta del servidor aquí, antes de continuar.
|
||||
|
||||
Aquí hay un video rápido sobre el uso de `async/await`:
|
||||
|
||||
[] (https://youtube.com/watch?v=YwmlRkrxvkk "Async y Await para administrar promesas")
|
||||
|
||||
Usamos la API `fetch()` para enviar datos JSON al servidor. Este método toma 2 parámetros:
|
||||
|
||||
- La URL del servidor, por lo que volvemos a colocar `//localhost:5000/api/accounts` aquí.
|
||||
- La configuración de la solicitud. Ahí es donde establecemos el método en `POST` y proporcionamos el `body` de la solicitud. Como estamos enviando datos JSON al servidor, también necesitamos establecer el encabezado `Content-Type` en `application/json` para que el servidor sepa cómo interpretar el contenido.
|
||||
|
||||
Como el servidor responderá a la solicitud con JSON, podemos usar `await response.json()` para analizar el contenido JSON y devolver el objeto resultante. Tenga en cuenta que este método es asíncrono, por lo que usamos la palabra clave `await` aquí antes de regresar para asegurarnos de que también se detecta cualquier error durante el análisis.
|
||||
|
||||
Ahora agregue un código a la función `register` para llamar a `createAccount()`:
|
||||
|
||||
```js
|
||||
const result = await createAccount(jsonData);
|
||||
```
|
||||
|
||||
Debido a que usamos la palabra clave `await` aquí, necesitamos agregar la palabra clave `async` antes de la función de registro:
|
||||
|
||||
```js
|
||||
async function register() {
|
||||
```
|
||||
|
||||
Finalmente, agreguemos algunos registros para verificar el resultado. La función final debería verse así:
|
||||
|
||||
```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 occured:', result.error);
|
||||
}
|
||||
|
||||
console.log('Account created!', result);
|
||||
}
|
||||
```
|
||||
|
||||
¡Eso fue un poco largo pero llegamos allí! Si abre sus [herramientas de desarrollo del navegador](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools) e intenta registrar una nueva cuenta, no debería ver ningún cambio en la página web pero aparecerá un mensaje en la consola confirmando que todo funciona.
|
||||
|
||||

|
||||
|
||||
✅ ¿Crees que los datos se envían al servidor de forma segura? ¿Y si alguien pudiera interceptar la solicitud? Puede leer sobre [HTTPS](https://en.wikipedia.org/wiki/HTTPS) para saber más sobre la comunicación segura de datos.
|
||||
|
||||
## Validación de datos
|
||||
|
||||
Si intenta registrar una nueva cuenta sin establecer un nombre de usuario primero, puede ver que el servidor devuelve un error con el código de estado [400 (Solicitud incorrecta)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400#:~:text=The%20HyperText%20Transfer%20Protocol%20(HTTP,%2C%20or%20deceptive%20request%20routing).).
|
||||
|
||||
Antes de enviar datos a un servidor, es una buena práctica [validar los datos del formulario](https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation) de antemano cuando sea posible, para asegurarse de enviar un solicitud válida. Los controles de formularios HTML5 proporcionan una validación incorporada utilizando varios atributos:
|
||||
|
||||
- `required`: el campo debe completarse; de lo contrario, el formulario no se podrá enviar
|
||||
- `minlength` y `maxlength`: define el número mínimo y máximo de caracteres en los campos de texto.
|
||||
- `min` y `max`: define el valor mínimo y máximo de un campo numérico.
|
||||
- `type`: define el tipo de datos esperados, como `number`, `email`, `file` u [otros tipos integrados](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). Este atributo también puede cambiar la representación visual del control de formulario.
|
||||
- `patrón`: permite definir un patrón [expresión regular](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) para probar si los datos ingresados son válidos o no.
|
||||
|
||||
> Consejo: puedes personalizar el aspecto de los controles de tu formulario dependiendo de si son válidos o no usando las pseudoclases CSS `:valid` y `:invalid`.
|
||||
|
||||
|
||||
### Tarea
|
||||
|
||||
Hay 2 campos obligatorios para crear una nueva cuenta válida, el nombre de usuario y la moneda, los otros campos son opcionales. Actualice el formulario en HTML para reflejar que:
|
||||
|
||||
```html
|
||||
<input name="user" type="text" required>
|
||||
...
|
||||
<input name="currency" type="text" value="$" required>
|
||||
```
|
||||
|
||||
Si bien esta implementación de servidor en particular no impone límites específicos en la longitud máxima de los campos, siempre es una buena práctica definir límites razonables para cualquier entrada de texto del usuario.
|
||||
|
||||
Agrega un atributo `maxlength` a los campos de texto:
|
||||
|
||||
```html
|
||||
<input name="user" type="text" maxlength="20" required>
|
||||
...
|
||||
<input name="currency" type="text" value="$" maxlength="5" required>
|
||||
...
|
||||
<input name="description" type="text" maxlength="100">
|
||||
```
|
||||
|
||||
Ahora, si presiona el botón *Registrar* y un campo no respeta una regla de validación que definimos, debería ver algo como esto:
|
||||
|
||||

|
||||
|
||||
Una validación como esta realizada *antes* de enviar cualquier dato al servidor se llama validación **del lado del cliente**. Pero tenga en cuenta que no siempre es posible realizar todas las comprobaciones sin enviar los datos. Por ejemplo, no podemos comprobar aquí si ya existe una cuenta con el mismo nombre de usuario sin enviar una solicitud al servidor. La validación adicional realizada en el servidor se denomina validación **del lado del servidor**.
|
||||
|
||||
Por lo general, ambos deben implementarse y, si bien el uso de la validación del lado del cliente mejora la experiencia del usuario al proporcionar comentarios instantáneos al usuario, la validación del lado del servidor es crucial para garantizar que los datos del usuario que manipula sean sólidos y seguros.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Desafío
|
||||
|
||||
Muestra un mensaje de error en el HTML si el usuario ya existe.
|
||||
|
||||
Aquí hay un ejemplo de cómo puede verse la página de inicio de sesión final después de un poco de estilo:
|
||||
|
||||

|
||||
|
||||
## [Prueba posterior a la conferencia](.github/post-lecture-quiz.md)
|
||||
|
||||
## Revisión y autoestudio
|
||||
|
||||
Los desarrolladores se han vuelto muy creativos en sus esfuerzos de creación de formularios, especialmente en lo que respecta a las estrategias de validación. Obtenga información sobre los diferentes flujos de formularios consultando [CodePen](https://codepen.com); ¿Puedes encontrar algunas formas interesantes e inspiradoras?
|
||||
|
||||
## Asignación
|
||||
|
||||
[Diseña tu aplicación bancaria](assignment.md)
|
13
7-bank-project/2-forms/translation/assignment.es.md
Normal file
13
7-bank-project/2-forms/translation/assignment.es.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Diseña tu aplicación bancaria
|
||||
|
||||
## Instrucciones
|
||||
|
||||
Cree un nuevo archivo `styles.css` y agréguele un enlace en su archivo `index.html` actual. En el archivo CSS que acaba de crear, agregue algunos estilos para que la página *Inicio de sesión* y *Panel de control* se vea bien y ordenada. Intente crear un tema de color para darle a su aplicación su propia marca.
|
||||
|
||||
> Consejo: puede modificar el HTML y agregar nuevos elementos y clases si es necesario.
|
||||
|
||||
## Rúbrica
|
||||
|
||||
| Criterios | Ejemplar | Adecuado | Necesita mejorar |
|
||||
| -------- | -------------------------------------------------- -------------------------------------------------- ------------------- | -------------------------------------------------- ---------------------------- | -------------------------------------------------- ------------------------------------------- |
|
||||
| | Todas las páginas se ven limpias y legibles, con un tema de color consistente y las diferentes secciones destacando correctamente. | Las páginas tienen un estilo pero sin un tema o con secciones no claramente delimitadas. | Las páginas carecen de estilo, las secciones se ven desorganizadas y la información es difícil de leer. |
|
Reference in New Issue
Block a user