miércoles, 30 de noviembre de 2016

Resumen videos Spring Boot 101 Parte 3/4. Thymeleaf y Angular

Como siempre damos las gracias a Dan Geabunea y su canal de videos. Hemos visto en una entrada anterior como pasar parámetros al "Model" de Spring. Thymeleaf, que es un sistema de plantillas para mostrar HTML, puede accedeer a estos parámetros del "Model". Veamos un poco como utilizar Thymeleaf, y mas tarde Angular 1.xx para dar mas protagonismo a la parte de la "Vista"

0. Indicar el acceso a una página Thymeleaf

Para ello tenemos que crear un controlador que contenga las anotaciones siguientes:

@Controller:
Anotación de clase que indica que es un controlador

@RequestMapping("/")
Anotación de clase o método  que indica donde localizar un servicio web

Además debemos actualizar el modelo para que Thymeleaf pueda acceder a estas variables que guarda el modelo.

package com.ximodante;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.ui.Model;

@Controller
public class ViewController {
 
 private String appMode;
 
 @Autowired
 public ViewController(Environment env){
  appMode=env.getProperty("app-mode");
 }
 
 @RequestMapping("/")
 public String index(Model model){
  model.addAttribute("datetime", new Date());
  model.addAttribute("username", "Informatica Dantesca");
  model.addAttribute("mode", "production");
  return "index";
 }

}


1. Crear una página Thymeleaf


Por otra parte, para mostrar una plantilla de Thymeleaf, tenemos que hacer estos pasos:

1. Colocar las librerías javascript o css que vayamos a utilizar en la carpeta scr/main/resources/static. Si queremos ser mas organizados se podran crear diferentes carpetas dentro de static (por ejemplo una para los "css",  otra para los "js", etc). En nuestro caso vamos a descargar, desde sus respectivas webs:


2. Crear una plantilla Thymeleaf en la carpeta scr/main/resources/static/templates.  En nuestro caso le vamos a llamar index.html .

Vamos a ver pequeños detalles

2. Separación de comportamiento entre producción y desarrollo

En Thymeleaf haremos uso de las clausulas condicionales "if". En el modelo podemos incluir una variable llamada "mode" que tome valores "development" o "production". Si es en desarrollo, vamos a utilizar las librería "bootstrap.min.css", mientras en producción vamos a utilizar "bootstrap.css". Para ello incluimos el siguiente código:

  <link th:if="${mode == 'development'}" rel="stylesheet" href="../static/bootstrap.css" th:href="@{/bootstrap.css}" />
  <link th:if="${mode == 'production'}" rel="stylesheet" href="../static/bootstrap.min.css" th:href="@{/bootstrap.min.css}" />

Thymeleaf también permite formatear variables. En este caso la fecha (que en el modelo la hemos guardado con el nombre "datetime"

  <p th:text="${#dates.format(datetime,'dd MMM yyyy HH:mm:ss')}" class="text-muted">Page was rendered today.</p>

3. Inclusión de código Angular 1.xx en la plantilla

No es mi misión explicar como va Angular. Pero veamos algunos detalles:
Indicación de la aplicación y módulo de código realizados en Angular, en nuestro caso lo hemos indicado en el <body>. Observar que el controlador tiene el alias "vm".


  <body ng-app="app" ng-controller="BookingsController as vm">


Para ver el contenido de las variables en angular hemos utilizado {{vm.variable}} o similar.
Tambien utilizamos la archirepetida cláusula ng-repat

El contenido de la plantilla Thymeleaf va a ser el siguiente:


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">

 <head>
  <meta charset="UTF-8" />
  <title>Hotel Booking App</title>
  <link th:if="${mode == 'development'}" rel="stylesheet" href="../static/bootstrap.css" th:href="@{/bootstrap.css}" />
  <link th:if="${mode == 'production'}" rel="stylesheet" href="../static/bootstrap.min.css" th:href="@{/bootstrap.min.css}" />
  <script type="text/javascript" src="/static/angular.min.js" th:src="@{angular.min.js}"></script>
  <script type="text/javascript" src="/static/app/module.js" th:src="@{/app/app.module.js}"></script>
  <script type="text/javascript" src="/static/app/bookings.controller.js" th:src="@{/app/bookings.controller.js}"></script>
 </head>
 
 <body ng-app="app" ng-controller="BookingsController as vm">
  <header>
   <nav class="navbar navbar-default">
    <div class="container-fluid">
     <a class="navbar-brand" href="#"> Booking Demo JAJAJAJA</a>
    </div>
    <p class="navbar-text navbar-right" th:text="'Signed as ' + ${username}" style="margin-right: 10px:">Signed as Anonymous</p>
   </nav>
  </header>
  
  Hello Bootstrap! How are you Folk? And you, Thymeleaf? 
  <div>{{vm.prova}}</div>
  
  <div>
   <div class="row">
    <div class="col-lg-offset-2 col-lg-8">
     <!-- Get all booking or only affordable ones -->
     <div class = "btn-group" role="group">
      <button ng-click = "vm.getAll()"        type="button" class = "btn btn-default">All</button>
      <button ng-click = "vm.getAffordable()" type="button" class = "btn btn-default">Less than {{vm.min}}</button>
     </div>
     <!--  Display bookings in a table -->
     <table class="table">
      <thead>
       <tr>
        <th>Hotel</th>
        <th>Nights</th>
        <th>Price</th>
        <th>Total</th>
        <th style="width: 90px"></th>
       </tr>
      </thead>
       <tr ng-repeat="booking in vm.bookings">
        <td>{{booking.hotelName}}</td>
        <td>{{booking.nbOfNights}}</td>
        <td>{{booking.pricePerNight}}</td>
        <td>{{booking.totalPrice}}</td>
        <td>
         <button class="btn btn-danger" ng-click="vm.deleteBooking(booking.id)">Delete</button>
        </td>
        
       </tr>
     </table>
    </div>
   </div>
  </div>
  
  <footer class="footer" style="position:absolute; bottom:0;background-color: #f5f5f5;">
   <div class="container">
    <p th:text="${#dates.format(datetime,'dd MMM yyyy HH:mm:ss')}" class="text-muted">Page was rendered today.</p>
   </div>
  </footer>
  
  

 </body>
</html>


4. Creación del código js de ángular

Para ello vamos a utilizar la carpeta scr/main/resources/static/templates para guardar 2 ficheros angular:

  • app.module.js (aplicación)
  • bookings.controller.js (controlador)

Normalmente en angular se tiene una aplicación y varios módulos que dependen de ella. En este caso solo tenemos una aplicación.

Veamos su código


(function(){
 'use strict';
 
 angular.module('app',[]);
})();


Poco puedo decir yo aquí. Veamos el otro código. Aquí hay que remarcar como hacemos peticiones GET y POST con ángular a nuestros servicios REST, que hemos definido

Veamos como hacemos una petición GET que nos devuleve una promesa:


function getAll(){
   var url = "/bookings/all";
   var bookingsPromise = $http.get(url);
   bookingsPromise.then(function(response) {
    vm.bookings = response.data;
   });
  }

Veamos como realiza una petición POST

function deleteBooking(id){
   var url = "/bookings/delete/" + id;
   $http.post(url).then(function(response){
    vm.bookings = response.data;
   });
   
  }


Tambien hay que publicar las funciones creadas:

vm.bookings = [];
  
  vm.getAll = getAll;
  vm.getAffordable = getAffordable;
  vm.deleteBooking = deleteBooking;
  vm.prova="Mi prueba";
  vm.min=23;


Y el contenido final del fichero js booking.controller.js es:

(function () {
 'use strict';
 
 angular
  .module('app')
  .controller('BookingsController',BookingsController);
 
 BookingsController.$inject = ['$http'];
 
 function BookingsController($http) {
  var vm = this;
  
  vm.bookings = [];
  
  vm.getAll = getAll;
  vm.getAffordable = getAffordable;
  vm.deleteBooking = deleteBooking;
  vm.prova="Mi prueba";
  vm.min=23;
  
  init();
  
  function init(){
   getAll();
  }
  
  function getAll(){
   var url = "/bookings/all";
   var bookingsPromise = $http.get(url);
   bookingsPromise.then(function(response) {
    vm.bookings = response.data;
   });
  }
  
  function getAffordable(){
   var url = "/bookings/affordable/" + vm.min;
   var bookingsPromise = $http.get(url);
   bookingsPromise.then(function(response) {
    vm.bookings = response.data;
   });
  }
  
  function deleteBooking(id){
   var url = "/bookings/delete/" + id;
   $http.post(url).then(function(response){
    vm.bookings = response.data;
   });
   
  }
 }
})();

No hay comentarios :

Publicar un comentario