> For the complete documentation index, see [llms.txt](https://shecodes.gitbook.io/she-codes-angular/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shecodes.gitbook.io/she-codes-angular/workshop-v.2/intermedio-2-formulario-de-autenticacion.md).

# Intermedio #2: Formulario de Autenticación 🧒

En este desafío vamos a divertirnos  creando un formulario de autenticación 🎯

## 💡 Introducción 💡

Como ya sabes inicializar una App de **Angular** en **Stackblitz**, omitiremos el primer paso de todos los desafíos anteriores (el paso 1 de crear la App de Angular)

&#x20;En este desafío nos divertiremos creando una App, donde haremos un formulario de autenticación.

[**¡Aquí puedes encontrar el demo!**](https://angular-logingithub.stackblitz.io)

¿Estás list@?

**Es hora de la Acción!!! 😝**

## Paso 1: Crearemos un formulario ✍️

Vamos a crear un formulario con un campo de texto, donde pondremos el nombre de usuario con el que nos vamos a autenticar en nuestra App. Adicionalmente tendrá un botón para enviar el texto que ingresaremos en el formulario.

Puedes añadir el siguiente código en **app.component.html**

{% code title="app.component.html" %}

```markup
<section>
  <h1>Autentiquemonos en Github 😉</h1>
  <form #form="ngForm" (ngSubmit)="login(form.value)">
    <div class="form-group">
      <input class="form-group"
        id="username"
        type="text"
        placeholder="Añade el nombre de usuario ..."
        required
        [(ngModel)]="model.username"
        name="username" />
    </div>
    <button type='submit'>Enviar!!</button>
  </form>
  <label class="label">Form Model: {{this.model | json}}</label><br />
</section>
```

{% endcode %}

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIH0rP7apVIxQnS2X%2F-LfwFbQokHWbp29OiBZg%2FScreen%20Shot%202019-05-27%20at%209.25.58%20PM.png?alt=media\&token=e41fe202-c10d-4ad0-bd1a-06e4c2d4cd87)

## Paso 2: Creemos la función que se encargará de la autenticación 🏭

En el archivo **app.component.ts** vamos a crear el objeto model, que nos mostrará el modelo de nuestro formulario y crearemos una función login que se encargará de la lógica de nuestra App.

{% code title="app.component.ts" %}

```typescript
import { Component } from '@angular/core';


@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  model = {};

  login() {
  
  }
}
```

{% endcode %}

En nuestra función llamada **login**, que será accionada cuando el usuario de click en el botón **Enviar**, le añadiremos un parámetro que va a recibir la función que se lo asignaremos a nuestra variable model.

{% code title="app.component.ts" %}

```
login(form: any) {
  this.model = form;
}
```

{% endcode %}

Deberías hacer algo así, y tu resultado se deberá ver así:👇

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIH0rP7apVIxQnS2X%2F-LfwCADtOu4n_7CEgKZ1%2FScreen%20Shot%202019-05-27%20at%209.10.57%20PM.png?alt=media\&token=1ca609e5-eae4-45c5-93c5-e15e6b8550ef)

## Paso 3: Crearemos un servicio 💆

Crearemos un 'servicio' dando clic sobre la carpeta 'app', seleccionamos 'service', nombramos el servicio como: '**login**', damos enter y se nos creará un archivo llamado: **login.service.ts**

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIH0rP7apVIxQnS2X%2F-LfwAImuxE5jZk-ZK-Kd%2FWebp.net-gifmaker%20\(9\).gif?alt=media\&token=48acb011-2163-4202-b4fb-1737666abb07)

Importamos unas dependencias en nuestro nuevo archivo llamado **login.service.ts**,  y añadimos en el constructor lo siguiente: **http: HttpClient**&#x20;

{% code title="login.service.ts" %}

```
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError as observableThrowError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';

@Injectable()
export class LoginService {

  constructor(private http: HttpClient) { }

}
```

{% endcode %}

Incluimos el '**HttpClientModule**' en el archivo **app.module.ts**

{% code title="add.module.ts" %}

```
import { HttpClientModule } from '@angular/common/http';
```

{% endcode %}

En los imports incluimos el **HttpClientModule** en el '**app.module.ts'**

{% code title="app.module.ts" %}

```
@NgModule({
  imports:      [ BrowserModule, FormsModule, HttpClientModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ],
  providers: [LoginService]
})
export class AppModule { }

```

{% endcode %}

En nuestro archivo **login.service.ts** crearemos dos funciones, una para manejar los errores: **handleError** y otra que nos obtendrá la data del API **getResponse**:

{% code title="login.service.ts" %}

```
getResponse(APIRoot: any) {
  return this.http
    .get<Array<{}>>(APIRoot)
    .pipe(map(data => data), catchError(this.handleError)); 
}

private handleError(res: HttpErrorResponse | any) {
  console.error(res.error || res.body.error);
  return observableThrowError(res.error || 'Server error');
}
```

{% endcode %}

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwLUSEh9frYN0uzKim%2FWebp.net-gifmaker%20\(11\).gif?alt=media\&token=a3ddc445-3012-4010-b80c-3e99a10e578d)

## Paso 4: Hagamos la lógica que llama a nuestro servicio  🍭

En nuestro archivo **app.component.ts**, crearemos una variable, de tipo **string,** donde le asignaremos la url del API.   En nuestra función **login**, crearemos un 'Observable' que nos permitirá subscribirnos a la petición que hacemos de los datos, usando la variable que definimos con la ruta del API de **Github**.

También importaremos en nuestro **app.component.ts** el servicio que creamos, **LoginService,** y crearemos una función **constructor** donde declararemos una función privada del servicio.&#x20;

{% code title="app.component.ts" %}

```typescript
import { Component } from '@angular/core';
import { LoginService } from './login.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  model = {};
  apiRoot: string = 'https://api.github.com/users/';
  
  constructor(private loginService: LoginService){}
  
  login(form: any) {
    this.model = form;
    console.log(this.model);
    this.loginService
      .getResponse(`${this.apiRoot}${this.model['username']}/repos`)
      .subscribe(
      response => (console.log(response)),
      error => (console.log('Ups! we have an error: ', error))
      )
  }
} 

```

{% endcode %}

Ahora podemos probar el llamado de nuestra API colocando en el campo de texto el nombre de un usuario de **Github**. Si abres la consola de **Stackblitz** podrás ver el resultado de nuestro **console.log(response)**.

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwOjl_u0TM1h7g8NLC%2FWebp.net-gifmaker%20\(12\).gif?alt=media\&token=8c1515cd-6ec4-4c32-ad25-fa063b856348)

## Paso 5: Mostremos el resultado del API 📰

Crearemos una variable llamada **reposList**, donde almacenaremos el resultado del llamado de nuestra API. Si observas la url de nuestra API, al final tiene '/**repos**', con esta palabra traeremos la lista de todos los repositorios del usuario que estamos consultando, puedes probar quitándole esta palabra y observarás que traerás la información de usuario (la imagen de perfil, su id en Github, entre otros datos) .

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwQlcibtjQSW7HeXpD%2FScreen%20Shot%202019-05-27%20at%2010.14.01%20PM.png?alt=media\&token=232aef69-2cf0-4e72-89e5-72c3a59dba3d)

Debajo de nuestra variable apiRoot, crearemos la variable **reposList** y en donde teníamos nuestro **console.log(response)**, lo reemplazaremos por: **this.reposList = response**

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwRyRIzY6kmJvyVltx%2FScreen%20Shot%202019-05-27%20at%2010.19.58%20PM.png?alt=media\&token=1a0c0f45-edec-47cd-a35a-b14562128bef)

Si quisiéramos mostrar el resultado en nuestra vista, en el html al final podríamos usar una interpolación de nuestra variable **reposList** añadiéndole a la interpolación un pipe **json**, veríamos algo como esto:

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwT5T8wxdXHzNazhW4%2FScreen%20Shot%202019-05-27%20at%2010.24.14%20PM.png?alt=media\&token=ec3e75eb-568e-418b-91c4-4c19979bbbf9)

Pero el resultado se mostraría muy desordenado y difícil de leer, así que haremos algo para mostrarlo más bonito.

## Paso 6: Tabla para mostrar los resultados 📋

Crearemos una tabla para mostrar  nuestro resultado y para ello vamos a crear un componente llamado tabla.

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwUVCQAdIC31STP1C9%2FWebp.net-gifmaker%20\(13\).gif?alt=media\&token=06176163-c7a2-4e49-a401-67b18228990a)

Iremos al archivo **table.component.html** y vamos a crear las etiquetas de tabla (**\<table>\<tr>\<td>\</td>\</tr>\</table>**)

En nuestra tabla crearemos una fila para los encabezados dónde vamos a mostrar un nombre, la descripción, el lenguaje del repo, la rama por defecto y la url.

{% code title="table.component.html" %}

```markup
<table class="table" id="reposTable">
  <thead>
    <tr>
      <th>#</th>
      <th>Name</th>
      <th>Description</th>
      <th>Language</th>
      <th>Default Branch</th>
      <th>Git Url</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
    </tr>
  </tbody>
</table>
```

{% endcode %}

Ahora vamos a añadir nuestro  componente tabla (**\<app-table>\</app-table>**) en nuestro componente App, en el archivo **app.component.html**&#x20;

![Añadimos nuestro componente tabla (\<app-table>)](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwaK5Ja-kr3Tf279YZ%2FScreen%20Shot%202019-05-27%20at%2011.00.20%20PM.png?alt=media\&token=cb145b90-9d21-4280-9167-c3a2f11435d8)

Ahora vamos a pasar la data de un componente a otro. Nuestro App component es el que tendrá toda la lógica de nuestra App, en Angular a estos componentes los llamamos **Smart Components** y a los componentes que no tienen una lógica como la de App y son mas sencillos (como para mostrar sólo data) los llamamos **Dumb Component.**

Dentro de **app.component.html** en el componente tabla, encontraremos el **app-table** donde vamos a hacer **binding** (pasaremos la data de un lugar a otro), crearemos un atributo **\[repos]** y le asignaremos nuestra variable **reposList.**

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-Lfwcj7IrS5TQowFNr2A%2FScreen%20Shot%202019-05-27%20at%2011.11.14%20PM.png?alt=media\&token=07055932-daf1-404a-b42a-9a37e072cb2f)

En el **table.component.ts** vamos a usar el decorador **@Input()**, para recibir la data del componente padre, del App.

{% hint style="info" %}
Un **decorador**, extiende una función mediante otra función, pero sin tocar aquella original, que se está extendiendo. El decorador recibe una función como argumento (aquella que se quiere decorar) y devuelve esa función con alguna funcionalidad adicional.
{% endhint %}

En el archivo **table.component.ts** vamos a importar el Input y recibimos la nueva data.

En la línea donde importamos el **Component**, vamos a añadirle el **Input**, nuestra línea quedaría así:&#x20;

{% code title="table.component.ts" %}

```

import { Component, Input, OnInit } from '@angular/core';
```

{% endcode %}

En la case **TableComponent** añadimos nuestro decorador **Input** con nuestro **repos** de tipo **array**.

{% code title="table.component.ts" %}

```
export class TableComponent implements OnInit {

  @Input() repos: [];

  constructor() { }
}


```

{% endcode %}

![](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-Lfwg-7Zpp6FJ86vYKAt%2FScreen%20Shot%202019-05-27%20at%2011.25.37%20PM.png?alt=media\&token=7791364d-7d17-48cb-9f1a-432b26854173)

Como en la respuesta podemos recibir más de un elemento en nuestro array, en nuestro HTML (**table.component.html**) usaremos la directiva **\*ngFor**, para recorrer todos los valores del array y usaremos la interpolación para colocar los valores que corresponde a cada columna.

{% code title="table.component.html" %}

```

<tbody>
    <tr *ngFor="let repo of repos; let i = index">
      <td>{{ i }}</td>
      <td>{{ repo['name'] }}</td>
      <td>{{ repo['description'] }}</td>
      <td>{{ repo['language'] }}</td>
      <td>{{ repo['default_branch'] }}</td>
      <td>{{ repo['git_url'] }}</td>
    </tr>
  </tbody>
```

{% endcode %}

![Agregamos un \*ngForm para recorrer el array que obtuvimos como respuesta del API](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwjtH2UhTjFzFp8haM%2FScreen%20Shot%202019-05-27%20at%2011.42.37%20PM.png?alt=media\&token=18e6fdff-d82d-40a0-a36e-83012af5ff61)

Para ocultar los encabezados podríamos añadirle la directiva **\*ngIf** en nuestro componente de tabla, para que solo muestre la tabla cuando tenga algún resultado, nos quedaría algo como esto:👇

![Añadimos el \*ngIf](https://3418570209-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LW1Rd6Lo-WMisT20MSI%2F-LfwIwypGd5kAaJkA2s1%2F-LfwlCS-uf-lVwH1w5dN%2FScreen%20Shot%202019-05-27%20at%2011.48.24%20PM.png?alt=media\&token=3086d9e4-9adc-478f-9dbb-20ed9a45ca9a)

## 🤓¡Tu Misión!🤓

Tenemos una misión para ti y es que pongas bonita la App, en ejercicios pasados hemos añadido CSS para poner los campos de texto y los botones más bonitos, incluso ya sabes poner imágenes.

La idea es que le pongas algo de CSS al mini formulario y a la tabla.

Para la tabla te daremos un poco de ayuda con una página que te permite generar estilos para las tablas:

{% embed url="<https://divtable.com/table-styler/>" %}

Solo necesitas copiar los estilos en el archivo **table.component.css** y añadir las clases respectivas en el html **table.component.html**

¡Felicitaciones hemos terminado nuestro desafío!

🎉 ¡**LO LOGRASTE!** 🎉

{% hint style="info" %}
[**Aquí**](https://stackblitz.com/edit/angular-logingithub) puedes encontrar el ejercicio resuelto.
{% endhint %}

{% hint style="info" %}
**Nota:**

Si necesitas mentoría con este ejercicio puedes contactar a:

Vanessa M. Aristizabal\
Twitter: @vanessamarely\
Correo: <vanessamarely@gmail.com>
{% endhint %}

{% hint style="success" %}
Has completado este desafío y finalizado con todos los desafíos del taller **Felicitaciones**!! 🎉🎉🎉
{% endhint %}

&#x20;
