El camino a la web en Java con Play! - Parte 3

Bueno, esta es la tercera y última parte de la saga "El camino a la web en Java con Play!"...Después de esto tengo planeado hacer algo más interesante (una aplicación de blogging o alguna sugerencia que hagan), que intentaré de subir a GitHub o algún medio de distribución de código, para que hagan mejoras y sugerencias con el fin de aprender cada vez más.

En esta ocasión les hablaré de la tercer parte más importante del framework y de cierta manera la más interesante; éstas son las vistas y configuraciones.

A lo que te truje chencha

Cómo ya hemos explicado antes, Play! maneja el patrón MVC, si no lo sabes con Play! aprenderlo es ridículamente simple (de hecho, gracias a Rails fue que yo lo aprendí; y cómo Play! sigue una filosofía similar, creo que es posible que lo aprendas desde Play!).
Ahora una vista al directorio de nuestro proyecto:

find .
.
.
.
.
/app/views
/app/views/main.html
/app/views/errors
/app/views/errors/500.html
/app/views/errors/404.html
/app/views/Application
/app/views/Application/index.html
.
.
.

La estructura de las vistas es simple, tenemos un archivo "main.html", en el cual vamos a dejar nuestro layout principal, a este imporatermos los estilos css globales de nuestra aplicación. Tenemos también un directorio llamado "error" con dos archivos "500.html" y "404.html", los cuales son útiles para mostrar una vista cool cuando haya un error, ya sea por un recurso no encontrado (que es para estos casos que sirve el 404.html) o para errores internos del servidor (que es para estos casos que sirve el 500.html).

Ahora, tenemos también el directorio "Application", del cual cuelga un archivo llamado "index.html", lo que significa que para la acción index en el controlador Application se hará un render en las vistas dentro de "/views/Application/index.html". Sin embargo nosotros tenemos un controlador antes definido en la segunda entrega de ésta saga, llamado People; por lo que es necesario que creemos otro directorio que cuelgue de views llamado People y dentro de este directorio crearemos un archivo llamado "list.html", quedando la estructura cómo:

find .
.
.
.
.
/app/views
/app/views/main.html
/app/views/errors
/app/views/errors/500.html
/app/views/errors/404.html
/app/views/Application
/app/views/Application/index.html
/app/views/People
/app/views/People/list.html
.
.
.

Ahora veamos el archivo "main.html":

<html>
    <head>
        <!-- Obtenemos el título que se renderize desde la acción -->
        <title>#{get 'title' /}</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/main.css'}">
        <!-- Obtenemos los estilos específicos de la vista a la que llamamos -->
        #{get 'moreStyles' /}
        <link rel="shortcut icon" type="image/png" href="@{'/public/images/favicon.png'}">
        <!-- ¡Contamos con soporte jQuery out of box! -->
        <script src="@{'/public/javascripts/jquery-1.4.2.min.js'}" type="text/javascript" charset="utf-8"></script>
        <!-- Obtenemos los scripts (javascripts) específicos de la vista a la que llamamos -->
        #{get 'moreScripts' /}
    </head>
    <body>
        <!-- Obtenemos las etiquetas específicas de las vistas -->
        #{doLayout /}        
    </body>
</html>

Ahora, editemos el archivo "list.html" en el directorio "/app/views/People/list.html":

<!-- Heredamos todo el layout que se tiene desde "/app/views/main.html" -->
#{extends 'main.html' /}
<!--
Recuerdan el #{get 'title'} en "main.html", pues bien con set ponemos
el título y con get lo obtenemos de la vista que renderizamos
-->
#{set title:'Listado' /}
<input type="submit" id="create" value="Crear nuevo" />
#{ifnot personas}
    <h2>No hay personas aún</h2>
#{/ifnot}
<div id="trabajo"></div>
#{if personas}
    <div class="tabla">
    <div class="tabla_encabezado">
        <div class="tabla_encabezado_cell">    
                <div class="tabla_encabezado_cell"> Nombre </div>
                <div class="tabla_encabezado_cell"> Apellido </div>
                <div class="tabla_encabezado_cell"> </div>
               <div class="tabla_encabezado_cell"> </div>
        </div>
    </div>
    #{list items:personas, as: 'p'}
    <div class="row">
        <div class="cell"> ${p.nombre} </div>
        <div class="cell"> ${p.apellido} </div>
        <div class="cell"> <input class="edit" type="submit" value="Editar" id="${p.id}" /> </div>
        <div class="cell"> <input class="delete" type="submit" value="Eliminar" id="${p.id}" /> </div>
    </div>
    #{/list}
    </div>
#{/if}

Ahora veamos, fuera de los comentarios (que explican lo que hace tal o cual etiqueta) dentro de Play! (en las vistas) tenemos tags especiales que nos ayudan a extender la funcionalidad por ejemplo "#{list items:[colección], as:[nombre_del_objeto_iterado]}", nos permite iterar cada elemento ([nombre_del_objeto_iterado]) dentro de una colección ([colección]) cómo una lista. Es cómo un ciclo "foreach". Todas las etiquetas de Play! siguen el principio HTML (por cada etiqueta de apertura debe haber una de cierre o cerrarse a sí misma). Tenemos la etiqueta "#{if}" que funciona similar a la sentencia "if" en Groovy y en Ruby (¬¬, ¡ay @wishmaster77, siempre metiendo a Ruby en donde puedes!), en este caso lo usamos cómo un (en java):if(personas != null), sin embargo, al igual que en Groovy y que en Ruby, podemos utilizar métodos del objeto/variable que estamos comparando con la etiqueta "#{if}" por ejemplo:

#{if personas.size() < 8 }
    <p>Mira hay poquitas personas, de hecho son menos que 8</p>
#{/if}

Bien, pongamos un poco intersante esto y utilicemos algo de Ajax para crear, editar y eliminar, para esto haremos uso de la herramienta que en mi poca experiencia es la mejor librería de JavaScript. Ahora dentro del directorio de nuestra aplicación encontramos un directorio llamado "/public/javascripts", dentro de este directorio crearemos un archivo de JavaScript llamado "personas.js" con el siguiente contenido:

$(document).ready(function(){
    $('#create').click(function(){
        $("#trabajo").html("
                    <div class=\"tabla\">
                        <div class=\"tabla_renglon\">
                            <div class=\"tabla_celda\"> Nombre: </div>
                            <div class=\"tabla_celda\"> <input id=\"name\" type=\"text\"  /> </div>
                        </div>
                        <div class=\"tabla_renglon\">
                            <div class=\"tabla_celda\"> Apellido: </div>
                            <div class=\"tabla_celda\"> <input id=\"lastname\" type=\"text\"  /> </div>
                       </div>
                       <div class=\"tabla_renglon\">
                           <div class=\"tabla_celda\">
                               <input type="
hidden" id="oscuroAction" value="create" />
                            </div>
                         <div class=\"tabla_celda\"> <input id=\"executer\" type=\"submit\" /> </div>
                       </div>
                </div>
            "
);    
    });

    $('.edit').click(function(){
        $.post("/People/editar", {id: $(this).attr("toEdit"), function(response){
                $("#trabajo").html("
                    <div class=\"tabla\">
                        <div class=\"tabla_renglon\">
                            <div class=\"tabla_celda\"> Nombre: </div>
                            <div class=\"tabla_celda\"> <input id=\"name\" type=\"text\" value=\"\" + response.nombre /> </div>
                        </div>
                        <div class=\"tabla_renglon\">
                            <div class=\"tabla_celda\"> Apellido: </div>
                            <div class=\"tabla_celda\"> <input id=\"lastname\" type=\"text\" value=\"\" + response.apellido /> </div>
                       </div>
                       <div class=\"tabla_renglon\">
                           <div class=\"tabla_celda\">
                               <input type="
hidden" id="oscuroAction" value="edit" />
                               <input type="
hidden" id="oscuroId" value=\"\" + response.id />
                         </div>
                         <div class=\"tabla_celda\"> <input id=\"executer\" type=\"submit\" /> </div>
                       </div>
                </div>
            "
);
        } });
    });
   
    $('#executer').click(function(){
        if($('#oscuroAction').val() == "edit"){
            $.post("/People/commitEdit",
                {
                    id: $('#oscuroId').val(),
                    nombre: $('#name').val(),
                    apellido: $('#lastname').val()
                },
                function(response){
                    alert("Los cambios han sido cometidos =)");
                    location.reload();
                }
            );
        }else if($('#oscuroAction').val() == "create"){
            $.post("/People/create",
                {
                    nombre: $('#name').val(),
                    apellido: $('#lastname').val()
                },
                function(response){
                    alert("Ya se agregó el registro");
                    location.reload();
                }
            );
        }
    });
   
    $('.delete').click(function(){
        if( confirm("¿Estás así seguro seguro que quieres eliminar?") ){
            if( confirm("No, ya hablando enserio, ¿neta neta l@ quieres eliminar, si es bien chipocles?") ){
                alert("Orale pues, nomas no te quejes después");
                $.post("/People/eliminar", { id: $(this).attr('id') }, function(data){
                    alert("Registro eliminado con éTZito");
                    location.reload();
                });
            }
        }
    });
});

Expliquemos brevemente este chorísimo de código (tal parece una aplicación de escritorio), tenemos primero el $(document).ready(function(){});. Para aquellos que saben JavaScript a pelo, pues deducirán que es una manera de elegir al documento actual y en cuanto esté listo para trabajar se ejecutará la función que se le pasa cómo parámetro (la cuál es una closure, muy famosas últimamente por estos lares). Y pues no es nada más que eso.
Seguido tenemos algunos bloques:

  • $('.edit').click(function(){});
  • $('.delete').click(function(){});
  • $('#executer').click(function(){});
  • $('#create').click(function(){});

Explicación rápida de selectores en jQuery:
$() => Indica que vamos a seleccionar algún elemento (en jQuery TODO es un elemento).
$('.clase') => Seleccionamos a todos los elementos dentro del documento actual con la clase (en este caso) .clase
$('#elementoId') => Seleccionamos a el elemento que tenga cómo id (en este caso) #elementoId.
Son cómo las selecciones en CSS.
Ahora, dentro de cada bloque vemos algo cómo $.post('/una/url', { un: 'objeto', tipo: 'JSON'}, function(que_recibe_algo){ //algún tipo de código aquí }); , eso nos indica que por medio del método post, pasaremos los parámetros del objeto tipo JSON a la url especificada y al terminar de ejecutar dicha acción, haremos lo que decimos en la función anónima (closure). En algunos casos modificamos el dom, ingresamos datos a los controladores, etc. Sin embargo debemos restringir que sólo nos hagan paso de parámetros por POST y definir las url. Para eso vámonos a nuestro archivo, routes dentro de nuestro directorio conf y lo editaremos de la siguiente manera:

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET     /                                       People.list
POST    /People/commitEdit                      People.edit
POST    /People/eliminar                        People.delete
POST    /People/create                          People.create
POST    /People/editar                          People.editor

# Map static resources from the /app/public folder to the /public path
GET     /public/                                staticDir:public

# Catch all
*       /{controller}/{action}                  {controller}.{action}

Y ya con eso (al parecer), podemos utilizar nuestra nueva aplicación. Claro hay que aplicarle los estilos CSS para que lo muestre cómo una tablita y demás; lo haría pero creo que ya he mostrado lo importante. Y vean lo sencillo que es hacer una aplicación con un poco de AJAX, Java y Play! framework. Espero con la siguiente sorprenderles y hacer algo con Scala + Play! (la aplicación que les había dicho).

Espero que les haya gustado y pues cualquier duda aquí estamos.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de neko069

Muy interesante, y útil,

Muy interesante, y útil, quiero manifestarte mi agradecimiento por éste tipo de tutorías, a mí en lo particular me parece un excelente intro, además de despertar curiosidad para documentarse acerca del framework..
Thanks Wishmaster!!

Re: Muy Interesante, y útil,

Muchas gracias @neko069, que bueno que te haya agradado y pues cómo bien has dicho esto es sólo un intro, es llevarte a conocer el camino y ya tu decides si avanzarlo o no. Espero y les haya agradado y deseen seguir este camino. :D

Ayuda jquery

hola hace algunos meses empece a utilizar este framework y muy util y sencillo, pero ahora estoy tratando de usar el plugin jtable de jquery y requiere los datos en json pero no funciona con play framework, y como este plugin requiere un json con ciertos parametros no se como formarlo desde jquert no se si me pudieras auxiliar gracias

Re: ayuda jquery

Me suena al clásico problema que pasamos todos los que usamos (o hemos usado) play!. Y ese es las latas de las referencias en archivos estáticos. Para poderte ayudar mejor sería bueno que pusieras que es lo que te arroja firebug. Porqué de hecho yo uso para un proyecto en plugin para grids, pero, no sé si sea el mismo que estás usando. Necesito un poco más de detalles, y algo más de ayuda que nos brinda firebug y con todo gusto te ayudo :D