
# Express | Vistas Dinámicas
## Introducción
ExpressJS puede enviar texto al navegador con solo unas pocas líneas de código:
```javascript
var express = require('express');
var app = express();
app.get('/', (request, response, next) => {
response.send('hello world');
});
app.listen(3000);
```
También podemos enviar HTML más complejo al navegador:
:::info
:bulb: Nos referimos a los argumentos en el callback de nuestra ruta como `request` y` response` como demostración.
Estos se representan comúnmente como `req` y` res` en la documentación, por lo que los usaremos en el futuro.
:::
```javascript
app.get('/hello', (req, res, next) => {
res.send(`
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="stylesheets/style.css">
</head>
<body>
This is my second route
</body>
</html>
`);
});
```
De esta forma resultaría tedioso y complicado a medida que nuestra aplicación crezca. ¿Te imaginas que nuestro `app.js` tenga miles de líneas? ¡Tiene que haber una mejor manera!
En ExpressJS *-y en la mayoría de los frameworks-* puedes crear archivos específicamente para nuestro HTML. De esta forma, podemos mantener el HTML separado de la lógica de nuestra aplicación.
Estos archivos se llamarán **vistas**, y una vez que aprendamos a usarlos, simplemente podemos llamar a `res.render` en lugar de` res.send` y enviar un archivo HTML al navegador:
```javascript
app.get('/', (req, res, next) => {
res.render('index.html');
});
```
## Vistas dinámicas
Las vistas son plantillas específicamente para HTML. HTML es lo que verá el cliente en su navegador.
Para comenzar a usar vistas, debemos crear una carpeta dentro de nuestro proyecto llamada `views` para agruparlas. Crearemos nuestra primera vista `index.hbs`:
```
$ mkdir views
$ touch views/index.hbs
$ tree .
.
├── app.js
├── package.json
├── stylesheets
│ └── style.css
└── views
└── index.hbs
```
:::warning
:bulb: Observe que usamos una nueva extensión **.hbs** en lugar de **.html**.
La ventaja de separar las vistas es que separamos la lógica del servidor ExpressJS (rutas, configuración del servidor, inicio del servidor, etc.) y la presentación (HTML), haciendo nuestro código más manejable y bien estructurado.
:::
ExpressJS no sabrá por sí solo dónde decidimos agrupar nuestras vistas, pero hay una solución fácil. Podemos decirle a nuestra aplicación Express dónde buscar nuestras vistas:
```javascript
// creates an absolute path pointing to a folder called "views"
app.set('views', __dirname + '/views');
```
En Express, en lugar de usar HTML simple, podemos usar una versión más elegante de HTML: **`hbs`**, o **[Handlebars](http://handlebarsjs.com/)**.
En breve entraremos en más detalles sobre **HBS**, pero por ahora, asegúrese de instalarlo en nuestra aplicación:
```
$ npm install hbs --save
```
... Y decirle a nuestra aplicación Express que **HBS** se encargará de renderizar el HTML:
```javascript
app.set('views', __dirname + '/views');
app.set('view engine', 'hbs');
```
Abrimos el archivo `views/index.hbs` y le agregamos un poco de contenido:
```htmlmixed
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My first view</title>
<link rel="stylesheet" href="stylesheets/style.css">
</head>
<body>
<h1>Ironhacker Be Like</h1>
<img src="https://media.giphy.com/media/l0MYEqEzwMWFCg8rm/giphy.gif">
</body>
</html>
```
Finalmente, en lugar de `res.send()` tenemos que decirle a Express que envíe y muestre nuestra vista de `index` al cliente:
```javascript
app.get('/', (req, res, next) => {
// send views/index.hbs for displaying in the browser
res.render('index');
});
```
Cuando visitemos `localhost:3000`, veremos nuestro HTML renderizado!
## Handlebars

Como vimos en el ejemplo anterior, nuestro archivo tenía una extensión `.hbs`. Esta extensión se utiliza por la palabra *Handlebars*. [**Handlebars.js**](http://handlebarsjs.com/) es una biblioteca de JavaScript para crear plantillas limpias y sin lógica basadas en **[Moustache Templating Language](https://mustache.github.io/)**.
Una de las características esenciales de usar **Handlebars** es que podemos hacer que las plantillas sean dinámicas enviándoles información y usando esos datos para renderizar nuestra aplicación web.
El método `res.render()` puede tomar un parámetro adicional que contendrá un objeto JavaScript con información que podemos usar en la vista.
Veamos un ejemplo:
```javascript
// app.js
app.get('/', (req, res, next) => {
let data = {
name: "UCOM",
curso: "Interfaces Web"
};
res.render('index', data);
});
```
```htmlmixed
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Home</title>
</head>
<body>
<h1>Hola {{name}}!</h1>
<p>Bienvenido al curso de {{curso}}!!</p>
</body>
</html>
```
Cualquier clave pasada en el objeto estará disponible en la vista, con una variable del mismo nombre.
**`{{variableName}}`** significa que una variable se enviará al HTML que enviamos al cliente
Las plantillas son en su mayoría HTML, pero `HBS` las analizará y ejecutará JavaScript antes de que muestre el HTML final y lo envíe al navegador:

## Handlebars - Scaping HTML
Por defecto, Handlebars escapa a los valores HTML incluidos en una expresión con el `{{ }}`. Eso significa que si enviamos datos como este:
```javascript
app.get('/', (req, res, next) => {
let data = {
name: "UCOM",
curso: "<span>Interfaces Web</span>"
};
res.render('index', data);
});
```
Y lo imprimimos en nuestro archivo `HBS`:
```htmlmixed
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Home</title>
</head>
<body>
<h1>Hola {{name}}!</h1>
<p>Bienvenido al curso de {{curso}}!!</p>
</body>
</html>
```
Veríamos el contenido con las `<span>`:
Si no queremos que Handlebars escape de un valor, deberíamos usar triple llave: **`{{{ }}}`**.
```htmlmixed
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Home</title>
</head>
<body>
<h1>Hola {{name}}!</h1>
<p>Bienvenido al curso de {{{curso}}}!!</p>
</body>
</html>
```
## Built-In Helpers
Además de la función de plantilla dinámica, Handlebars nos brinda excelentes ayudantes para hacernos la vida más fácil al codificar nuestra web. :wink:
### El bloque `if`
Puede usar el bloque `if` para renderizar un bloque condicionalmente. Eso significa que, si su argumento devuelve "falso", "indefinido", "nulo", "" "," 0 "o" [] ", **Handlebars** no mostrará el bloque.
```javascript
app.get('/', (req, res, next) => {
let data = {
name: "UCOM",
};
res.render('index', data);
});
```
```htmlmixed
<h1>Hello {{name}}!</h1>
{{#if lastName}}
<h2>Esto no se va a mostrar!!</h2>
{{/if}}
```
Ya que `lastName` es `undefined`, nuestro tag `<h2>` no se va a mostrar! Ahora, agreguemos la propiedad `lastName` a los datos!
```javascript
app.get('/', (req, res, next) => {
let data = {
name: "UCOM",
lastName: "University"
};
res.render('index', data);
});
```
```htmlmixed
<h1>Hola {{name}} {{lastName}}!</h1>
{{#if lastName}}
<h2>Esto si se va a mostrar!!</h2>
{{/if}}
```
También podemos agregar una declaración `else`, ¡lo que hace que esto sea aún más poderoso!
```htmlmixed
<h1>Hola {{name}} {{lastName}}!</h1>
{{#if address}}
<h2>Esto no se va a mostrar!!</h2>
{{else}}
<h2>Esto no se va mostrar porque la propiedad `address` no existe!!</h2>
{{/if}}
```
### El bloque `unless`
Puede usar el bloque `unless` como el inverso del bloque `if`. Representará el bloque si la expresión devuelve un **valor falso**.
```htmlmixed
<h1>Hola {{name}} {{lastName}}!</h1>
{{#unless address}}
<h3>NO PODEMOS ENCONTRAR LA DIRECCIÓN!</h3>
{{/unless}}
```
:::info
Si buscar `address` en el contexto actual devuelve un **valor falso**, Handlebars mostrará el mensaje. De lo contrario, no mostrará nada. En nuestro ejemplo, mostrará el mensaje.
:::
Si agregamos la propiedad `address` el mensaje va a desaparecer!
```javascript
app.get('/', (req, res, next) => {
let data = {
name: "UCOM",
lastName: "University",
address: "Online"
};
res.render('index', data);
});
```
### El bloque `each`
El bloque `each` nos ayuda a iterar sobre una lista de elementos, principalmente` objetos` y `arrays`. Imagínese imprimir la lista de materias que tiene una carrera. Podemos hacer algo como esto:
```htmlmixed
<ul>
<li>Interfaces Web</li>
<li>Nuevas Tecnologías</li>
<li>Gestión de Proyectos</li>
<li>Sistemas operativos</li>
<li>Tecnologías</li>
<li>Programación Unix/Linux</li>
</ul>
```
Estamos repitiendo la misma etiqueta `<li>` seis veces, solo cambiando el contenido dentro de las etiquetas. Usando el bloque `each`, podemos hacer lo siguiente:
Primero, necesitamos pasar los datos a nuestra vista:
```javascript
app.get('/', (req, res, next) => {
let data = {
name: "UCOM",
lastName: "University",
address: "Online",
materias: ["Interfaces Web", "Nuevas Tecnologías", "Gestión de Proyectos", "Sistemas operativos", "Tecnologías", "Programación Unix/Linux"]
};
res.render('index', data);
});
```
Una vez que tenemos los datos en nuestro archivo `index.hbs`:
```htmlmixed
<ul>
{{#each materias}}
<li>{{this}}</li>
{{/each}}
</ul>
```
:::info
:bulb: Dentro del bloque, podemos usar `this` para hacer referencia al elemento que estamos iterando.
:::
Opcionalmente, puede proporcionar una sección `{{else}}` que se mostrará solo cuando la lista esté vacía.
```htmlmixed
<ul>
{{#each materias}}
<li>{{this}}</li>
{{else}}
<p>No hay ninguna materia!</p>
{{/each}}
</ul>
```
#### `@index`
Al recorrer los elementos de `each`, opcionalmente puedes hacer referencia al **índice** del ciclo actual a través de` {{@index}} `
```htmlmixed
<ul>
{{#each materias}}
<li>{{@index}}: {{this}}</li>
{{/each}}
</ul>
```
#### `@key`
Además, para la iteración del `object`,` {{@key}} `hace referencia al nombre de la clave actual:
```htmlmixed
{{#each object}}
{{@key}}: {{this}}
{{/each}}
```
#### `@first` - `@last`
Los primeros y últimos pasos de la iteración se anotan mediante las variables `@first` y` @last` cuando se itera sobre una matriz.
```htmlmixed
<ul>
{{#each materias}}
{{#if @first}}
<li><b>{{this}}</b></li>
{{else if @last}}
<li><i>{{this}}</i></li>
{{else}}
<li>{{this}}</li>
{{/if}}
{{/each}}
</ul>
```
:::info
Es importante notar que los ayudantes `@first` y` @last` devuelven un boolean! Al iterar sobre un objeto, solo `@first` está disponible.
:::
### El bloque `with`
Por lo general, Handlebars evalúa su plantillas frente al contexto pasado al método compilado. Podemos cambiar ese contexto a una sección de una plantilla usando el bloque incorporado `with`.
Por ejemplo, pasando los siguientes datos:
```javascript
app.get('/', (req, res, next) => {
let data = {
name: "UCOM",
lastName: "University",
address: {
street: "Dr Juan Eulogio Estigarribia",
number: 32
},
materias: ["Interfaces Web", "Nuevas Tecnologías", "Gestión de Proyectos", "Sistemas operativos", "Tecnologías", "Programación Unix/Linux"]
};
res.render('index', data);
});
```
Podemos hacer esto:
```htmlmixed
<h1>Hola {{name}} {{lastName}}!</h1>
{{#with address}}
<p>{{street}}, {{number}}</p>
{{/with}}
```
:::info
Usando el bloque`with`, cambiamos el contexto, entonces nos podemos referir a `{{address.street}}` y `{{address.number}}`, como `{{street}}` y `{{number}}`.
:::
## Recursos extra
- [HandlebarsJS documentation](http://handlebarsjs.com/)