miércoles, 27 de agosto de 2014

Convertir una maqueta en HTML en una página Web con contenido dinámico (2)

En el post anterior hablábamos del proceso para convertir una maqueta en HTML con una cantidad fija de información en una Web con contenido dinámico. Ahora, veremos cómo convertir una maqueta con una cantidad variable de información en una Web con contenido dinámico.

Ejemplo de sección con una cantidad variable de información


Volviendo al ejemplo de la Web de la escuela, supongamos que hay una página en la que se publica la lista de estudiantes que cumplen años en un día determinado. Para ello, será posible indicar una fecha y pulsar un botón  para obtener la lista de alumnos correspondientes. La sección maquetada podría quedar como sigue:

<div id="cumples">
    <input type="date"> <button>Buscar</button>
    <ul>
        <li>
            <img src="img/persona.png">
            <label>Juan Pérez</label>
        </li>
        <li>
            <img src="img/persona.png">
            <label>Manuel López</label>
        </li>
        <li>
            <img src="img/persona.png">
            <label>María González Gurrierrez</label>
            </li>
        <li>
            <img src="img/persona.png">
            <label>Clara Martínez</label>
            </li>
        <li>
            <img src="img/persona.png">
            <label>Julián del Corral</label>
        </li>
    </ul>
</div>

Cuyo resultado es el siguiente (después de formatearlo un poco con CSS):



Supongamos ahora que en dicha Web, hay un servicio REST que, al consultarlo indicándole una fecha, devuelve un JSON la lista de los alumnos que cumplen años. Por ejemplo, el JSON devuelto podría tener la estructura siguiente

[
    {
        "nombre": "María López González",
        "foto": "img/alumnos/maria_lopez.jpg"
    },
    {
        "nombre": "Juan Pérez González",
        "foto": "img/alumnos/juan_perez.jpg"
    },
    {
        "nombre": "Laura Gutierrez Pérez",
        "foto": "img/alumnos/laura_gutierrez.jpg"
    }
]

Veamos ahora, cómo transformar la maqueta para mostrar dinámicamente el contenido del JSON obtenido desde el servicio REST.

Proceso para convertir el contenido de una maqueta en HTML con una cantidad variable de información en una Web con contenido dinámico


Hay varias formas para generar una cantidad dinámica de contenido, aunque todas requieren lo mismo: insertar nuevos elementos en la página. Ahora, la forma de hacer estas inserciones, puede variar mucho. En el post XXX se muestra cómo insertar nodos nuevos (etiquetas HTML) mediante jQuery. Aunque el método ahí mostrado es más flexible y potente que el que mostraremos a continuación, el que sigue es más simple y directo; siendo un paso previo natural al uso de frameworks para el uso de plantillas HTML, como Mustage.

Entonces, el proceso sería el siguiente:

  1. Identificar el evento ante el cuál queremos actualizar la plantilla con los datos dinámicos.
  2. Localizar la sección de datos que se repiten
  3. Modificar la plantilla:
    1. Eliminar todos los elementos que se repiten, excepto el primero
    2. Si no lo están, encerrar los datos que se repiten en un elemento agrupador.
    3. Asignar un identificador único al elemento agrupador.
    4. Crear un bloque script con un identificador único y tipo "text/html"
    5. Mover el primer conjunto de datos que se repite, localizado en el paso 2, al bloque script del paso 3 - 4.
    6. Remplazar cada texto o atributo a modificar dinámicamente por el nombre del dato desde donde se extraerá, encerrado entre llaves dobles.
  4. Crear una cadena en JavaScript con la plantilla del HTML que deberá repetirse, extrayéndolo del contenido de la etiqueta script, del paso 3 - 4.
  5. Crear una función JavaScript para generar HTML, a partir de una plantilla HTML. Para ello, deberá recibir una cadena con una plantilla de una estructura HTML, un diccionario con el valor a remplazar por cada nombre de la plantilla, y deberá devolver una cadena con el HTML resultante de los remplazos.
  6. Crear una función JavaScript que modifique el HTML de la página para mostrar una lista de datos. Para ello, para cada elemento de la lista y para cada dato de dicho elemento: llamar a la función del paso 5, indicándole la plantilla HTML del paso 4, el nombre del dato y el dato en sí.
  7. Crear una función en JavaScript que cargue los datos que se quieren mostrar y llame a la función del paso 6 con los datos cargados.
  8. Cuando se produzca el evento deseado (identificado en el paso 1), llamar a la función de carga de datos (creada en el paso 7).
  9. Fin.

Para ilustrar el proceso anterior, veamos cómo dinamizar los datos de la plantilla de los "alumnos que cumplen año".

Ejemplo del proceso, ilustrado y explicado, paso a paso


1 Identificar el evento ante el cuál queremos actualizar la plantilla con los datos dinámicos


En la Web de lista de alumnos que cumplen años, primero hay que seleccionar la fecha del cumpleaños en cuestión y luego pulsar el botón de búsqueda; por lo que el evento para actualizar la plantilla será cuando se pulse en el botón para buscar.

2 Localizar la sección de datos que se repiten


En este caso, los datos que se repiten son la foto y el nombre, que se corresponden con una etiqueta img y label, encerradas por una etiqueta li. Por lo tanto, la sección de datos que se repiten son las etiquetas li y su contenido:

<li>
    <img src="img/persona.png">
    <label>Juan Pérez</label>
</li>
<li>
    <img src="img/persona.png">
    <label>Manuel López</label>
</li>
<li>
    <img src="img/persona.png">
    <label>María González Gurrierrez</label>
</li>
<!-- ... -->

3 - 1 Eliminar todos los elementos que se repiten, excepto el primero


En este caso, la lista pasaría de tener varios li, a tener uno solo:

<ul>
    <li>
        <img src="img/persona.png">
        <label>Juan Pérez</label>
    </li>
</ul>

3 - 2 Si no lo están, encerrar los datos que se repiten en un elemento agrupador


La sección que se repite es la contenida por las etiquetas li que están contenidas por una etiqueta ul; por lo que no es necesario encerrarlas en  ningún elemento agrupador. Si en lugar de una etiqueta li, la sección repetida fuera un div, por ejemplo, es posible que hubiera que encerrarlo en otro div; por ejemplo. No obstante, en este caso, los datos que se repiten ya están encerrados en un elemento agrupador: ul.

3 - 3 Asignar un identificador único al elemento agrupador


Ya que el elemento agrupador es la etiqueta ul y ésta contiene la lista de alumnos que cumplen años, identificaremos a dicho elemento con el id "alumnos":

<ul id="alumnos">
    <li>
        <img src="img/persona.png">
        <label>Juan Pérez</label>
    </li>
</ul>

3 - 4 Crear un bloque script con un identificador único y tipo "text/html"


El bloque script será el contenedor de la plantilla de los datos que se repiten para cada alumno y, aunque puede estar en cualquier parte de la página, es una buena práctica ponerlo lo más cerca posible de la zona donde vamos a insertar los datos posteriormente:

<ul id="alumnos">
    <li>
        <img src="img/persona.png">
        <label>Juan Pérez</label>
    </li>
</ul>
<script id="plantillaAlumno" type="text/html">
</script>

3 - 5 Mover el conjunto de datos que se repite (localizado en el paso 2), al bloque script del paso 3 - 4


Aquí se trata, simplemente de mover la etiqueta li y su contenido, hacia dentro de la etiqueta script del paso anterior:

<ul id="alumnos">
</ul>
<script id="plantillaAlumno" type="text/html">
    <li>
        <img src="img/persona.png">
        <label>Juan Pérez</label>
    </li>
</script>

3- 6 Remplazar cada texto o atributo a modificar dinámicamente por el nombre del dato desde donde se extraerá, encerrado entre llaves dobles


En este punto modificaremos cada elemento que deba cambiar dinámicamente por el nombre de la variable o el atributo del objeto en el que tendremos dicha información en JavaScript. En este caso, se trata de la Url de la fotografía y del nombre del estudiante por lo que la plantilla quedaría, finalmente, así:

<div id="cumples">
    <input id="fecha" type="date"> <button id="buscar">Buscar</button>
    <ul id="alumnos">
    </ul>
    <script id="plantillaAlumno" type="text/html">
        <li>
            <img src="{{foto}}">
            <label>{{nombre}}</label>
        </li>
    </script>
</div>

El motivo para poner el nombre del dato encerrado en llaves dobles es evitar colisiones entre el nombre de nuestra variable y elementos válidos del HTML, de modo que, cuando generemos el contenido dinámico no sustituyamos por accidente una parte de nuestra estructura HTML. Del mismo modo, encerramos nuestra plantilla en una etiqueta script con tipo "text/html" para que el marcado HTML de la plantilla no genere ningún elemento visual que deforme la información de la página.

4 Crear una cadena con la plantilla del HTML que deberá repetirse, extrayéndolo del contenido de la etiqueta script, del paso 3 - 4.


La cadena la crearemos extrayendo el contenido de la etiqueta script identificada como plantilla:

var plantillaAlumno = $('#plantillaAlumno').html();

5 Crear una función JavaScript para generar HTML, a partir de una plantilla HTML.


La función que se ilustra a continuación es un elemento reaprovechable del proceso; es decir: que podremos usar esta función en cualquier caso, independientemente del marcado HTML que hayamos puesto en la plantilla, siempre y cuando, cumplamos con encerrar entre llaves dobles los nombres de los datos a remplazar. De modo que, el siguente es un código que podremos copiar y pegar de una Web a otra sin ningún cambio:

/**
 * Genera código HTML a partir de una plantilla y datos de sustitución
 * @param {string} pantilla - Cadena con la plantilla HTML
 * @param {Object} datos - Diccionario de nombres de datos a remplazar 
 *      con su respectivo valor
 */
function generarHtml(plantilla, datos) {
    var html = plantilla;                   // Inicializar el HTML
    var nombresDeDatos = Object.keys(datos);// Obtener lista de datos a remplazar
    nombresDeDatos.forEach(function (nombreDato) {  // Por cada dato a remplazar:
        var nombre = new RegExp('{{' + nombreDato + '}}', 'g'); // Obtener nombre
        var valor = datos[nombreDato];              // Obtener valor de remplazo
        html = html.replace(nombre, valor);         // Remplazar nombre por valor
    });
    return html;                                    // Devolver HTML generado
}

6 Crear una función JavaScript que modifique el HTML de la página para mostrar una lista de datos


Esta función, básicamente llamará a la función del paso anterior, por cada elemento a mostrar e insertará en el DOM el HTML generado con cada dato:

/**
 * Actualiza la lista de alumnos cuyo cumpleaño coincide con la fecha indicada
 * @param {object[]} listaAlumnos - Lista de objetos con los datos de los
 *      alumnos: nombre y foto
 */
function actualizarListaAlumnos(listaAlumnos) {
    $('#alumnos').html('');                  // Inicializar la lista HTML
    listaAlumnos.forEach(function (alumno) { // Por cada alumno:
        var html = generarHtml(plantillaAlumno, alumno); // Generar su HTML
        $('#alumnos').append(html);          // Añadir el HTML generado a la Web
    });
}

7 Crear una función en JavaScript que cargue los datos que se quieren mostrar y llame a la función del paso 6 con los datos cargados


Como hemos supuesto que existe un servicio REST que, dada una fecha, devuelve un JSON con la lista de alumnos que cumplen años en dicha fecha, vamos a necesitar:


  1. Identificar la Url del servicio REST
  2. Construir la Url de la consulta con la fecha seleccionada
  3. Pedir los datos JSON mediante Ajax
  4. Llamar a la función del paso 6, con los datos obtenidos.

Para simplificar, supongamos que el servicio REST está en la misma Web, en la Url relativa "api/cumpleanyos" y que llamaremos a la función actualizarListaAlumnos, quedando la función como sigue:

/**
 * Carga la lista de alumnos que cumplen años y actualiza la interfaz 
 * con los datos cargados
 */
function cargarCumpleanyos() {
    var fecha = $('#fecha').val();          // Obtener fecha de consulta
    var url = '/api/cumpleanyos/' + fecha;  // Generar Url de consulta
    $.getJSON(url, function (result) {      // Solicitar lista de alumnos
        if (result) {                       // Si se obtiene alguna lista
            actualizarListaAlumnos(result); // Actualizar lista de alumnos
        }
    });
}

8 Cuando se produzca el evento deseado (identificado en el paso 1), llamar a la función de carga de datos (creada en el paso 7).


Finalmente, el evento generado por el usuario que desencadena la ejecución de la búsqueda y la actualización dinámica de los contenidos de la página:

$('#buscar').click(cargarCumpleanyos);

Poniéndolo todo junto 


Para ver el resultado completo de todo lo anterior, ir a los siguiente enlaces, donde están las páginas funcionando y el código fuente de las mismas:



Conclusiones y siguientes pasos


La dinamización de una maqueta en HTML que deba tener una cantidad variable de elementos repetitivos es más compleja que la de una maqueta con una cantidad fija de elementos y requiere una reestructuración de la maqueta. Sin embargo, con organización y metódica pueden obtenerse muy buenos resultados con muy poco código en JavaScript, reduciéndose el proceso en general a:

  1. Modificar la maqueta para:
    1. Prepararla para su actualización desde JavaScript.
    2. Crear una plantilla de los elementos repetitivos.
  2. Crear funciones en JavaScript para cargar y visualizar el contenido dinámico, remplazando en la plantilla los valores cargados.
  3. Ejecutar las funciones de carga y visualización, luego de la ejecución de un evento determinado.

Ahora, una vez vista la forma de generar estos contenidos dinámicos de forma manual, lo siguiente es aprender a hacerlo usando un framework o librería apropiados para esta tarea que, con toda seguridad, nos facilitará el proceso y proveerá de muchas más opciones.

Una buena opción para continuar es el tutorial interactivo de Knockout disponible en http://learn.knockoutjs.com, donde enseñan los conceptos y la práctica de la separación de la presentación de la información, de la lógica de su operación, mientras aprendemos a usar la biblioteca.



Si te ayudó este tutorial, compártelo con otros y si tienes alguna sugerencia o cambio para mejorarlo... haz tus comentarios.

1 comentario:

  1. Parece sencillo, y es más o menos lo que buscaba, gracias por compartir.

    ResponderEliminar