Se solicita información sobre el paradero del estudiante Arshak Karhanyan

Clase 18

Viernes (Noche, 2022)

Resumen

En esta clase seguimos trabajando con Spark, entendiendo como las páginas tienen tanto fragmentos de código repetitivos como estructuras generales conocidas como Layouts, y como las plantillas (templates) y los elementos block y partial de Handlebars nos pueden ayudar a no repetir lógica de vista.

Además, repasamos qué son los formularios, cómo podemos hacer formularios de creación de recursos con HTML y HTTP, y qué implicancias tienen desde el punto de vista del acceso al contexto de persistencia.

Fragmentos y Layouts

partials/fragmentos/componentes (control directo) vs layouts (inversión de control)

Problema: ¡Código repetido! Solución: ¡depende!. ¿Es el código repetido una estructura general para toda la aplicación, o al menos una parte de ella? ¿O se trata de fragmentos que aparecen con alguna frecuencia, en lugares diferentes, pero sin obedecer a una estructura general?

Dependiendo el caso, estamos hablando de un fragmento/componente (partial) o un layout (disposición).

Layouts

Los layouts nos proponen una forma de reutilizar el código HTML definiendo (al menos un) archivo que hace de marco general y define puntos de extensión o “huecos”, que las vistas completarán.

No serán estos marcos generales quienes invoquen a las vistas, sino las vistas quienes se enmarcarán en nuestros layouts.

Para implementar esta idea, por un lado, en nuestras vistas tenemos que invocar el layout:

{{> layout.html.hbs }}

Por otro lado, tenemos que crear nuestro archivo layout.html.hbs, con uno o más “huecos” nombrados, al mejor estilo template-method:

{{# block "principal" }}
{{/block}}

Link al código completo

Luego, volveremos a la la vista en que nos interesa aplicar ese layout, y utilizaremos partial para llenar esos huecos:

{{# partial "principal" }}
{{/partial}}

Link al código completo

Fragmentos

Nuestros fragmentos son archivos con porciones de HTML que invocamos directamente desde nuestra vista para que nos aporten un fragmento (justamente) de código reutilizable. Los implementamos usando la misma sintaxis, sólo que no tienen huecos:

{{> contratanos.html.hbs }}

Link al código completo

Estos fragmentos definirán componentes HTML reutilizables, como por ejemplo, un botón contratanos genérico que insertaremos en más de un lugar de la página:

<!-- Probablemente sea un poco más complejo-->
<a href="/....">Contratanos (...)</a>

Link al código completo

Alternativamente, podemos registrar helpers, que son pequeñas funciones que extienden la sintaxis de Handebars:

HandlebarsTemplateEngine engine = new HandlebarsTemplateEngine() {
    {
        this.handlebars.registerHelper("holaMundo", (o, options) -> {
            return "hola mundo";
        });
    }
};

Luego de hacer esto, podremos usarlo en nuestros templates:

{{holaMundo}}

Paréntesis: repaso breve de las estructuras de control

Iteración:

{{#each consultoras}}
    <li>{{nombre}}</li>
{{/each}}

o también:

{{#consultoras}}
    <li>{{nombre}}</li>
{{/consultoras}}

Forms de guardado y transacciones

  • REST: POST /consultoras vs GET /consultoras/nueva
// el primero muestra el formulario
Spark.get("/consultoras/nueva", consultorasController::nueva, engine);
// el segundo es quien recibe la información del formulario y crea al objeto
Spark.post("/consultoras", consultorasController::crear);
  • Formularios de creación: indicar el uso del método POST.
<form method="POST" action="/consultoras">
    <label for="nombre">Nombre</label>
    <input name="nombre" type="text">

    <label for="cantidadEmpleados">Cantidad de empleados</label>
    <input name="cantidadEmpleados" type="number" min="1" max="100" >

    <input type="submit">
</form>
  • Importancia de redirigir luego de un POST en una aplicación Web (o devolver 201 en un API). Si no, es fácil generar sitios propensos a envíos duplicados de formularios:
  public Void crear(Request request, Response response) {
    // ...
    response.redirect("/");
    return null;
  }
  • Manejo declarativo de transacciones. No usar explícitamente transaction.begin(), transaction.commit(), transaction.rollback(). En su lugar utilizar TransactionalOps y withTransaction:
public class ConsultorasController implements WithGlobalEntityManager, TransactionalOps {

  // ...

  public Void crear(Request request, Response response) {
    withTransaction(() -> {
      Consultora consultora = new Consultora(
              request.queryParams("nombre"),  // no confundirse! Aunque el método se llama
                                              // queryParam, en realidad son body params
              Integer.parseInt(request.queryParams("cantidadEmpleados")));
      RepositorioConsultoras.instancia.agregar(consultora);
    });
    // ...
  }

Material