Tempo.js, motor de renderización de plantillas HTML con JSON. Ejemplo con ASP.NET

Tempo es una librería javascript que nos va a permitir renderizar datos en formato JSON sobre plantillas de HTML. Renderizar los datos sobre plantillas de HTML nos va a permitir separar completamente la presentación de la lógica necesaria para la obtención de los datos.

Vamos a verlo con un ejemplo. Para serializar objetos .NET a JSON vamos a utilizar la librería JSON.NET., jQuery como librería Ajax y Tempo.js para las plantillas HTML.

Realizamos los siguientes pasos:

  • Con Visual Studio 2010 creamos un nuevo sitio web. Añadimos una página aspx, Home.aspx.
  • Añadimos la referencias a jQuery y JSON.NET, preferiblemente utilizando nuget.
  • Añadimos la referencia a Tempo.js, lamentablemente en estos momentos no existe un package de nuget para Tempo.js, por lo que tendremos que descargar manualmente la librería y añadir los archivos tempo.js y tempo.min.js manualmente a nuestro sitio.

Para poder realizar nuestro ejemplo lo primero es, sobre App_Code, crear una clase persona , que será el objeto que devolveremos en JSON.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;


public class Persona
{
    public Persona(string nombre, string apellidos, DateTime fechaNacimiento)
    {
        Id = Guid.NewGuid();
        Nombre = nombre;
        Apellidos = apellidos;
        FechaNacimiento = fechaNacimiento;
    }

    public Guid Id { get; set; }
    public string Nombre { get; set; }
    public string Apellidos { get; set; }
    public DateTime FechaNacimiento { get; set; }

}
La clase es sencilla, pero hemos incluido un campo DateTime que nos va a dar problemas. Lo hemos hecho a proposito para ilustrar  el modo de trabajar con fechas en JSON …

Ahora creamos un handler que nos devolverá una colección de personas. Este handler es el que invocaremos desde la página Home.aspx para mostrar los datos

<%@ WebHandler Language="C#" Class="PersonasDataHandler" %>

using System;
using System.Web;
using System.Collections.Generic;

public class PersonasDataHandler : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "application/json";


        var personas = new  List<Persona>();
        for (int i = 0; i < 500; i++)
        {
            personas.Add(new Persona("Nombre " + i, "Apellido " + i, DateTime.Now.AddDays(i*(-1))));
        }

        var json = Newtonsoft.Json.JsonConvert.SerializeObject(personas, 
new CultureDateTimeConverter(CurrentCulture)); context.Response.Write(json); } public System.Globalization.CultureInfo CurrentCulture { get { return System.Threading.Thread.CurrentThread.CurrentUICulture; } } public bool IsReusable { get { return false; } } }

Fijémonos en que a la hora de serializar la colección de personas, utilizamos una de las sobrecargas del método SerializeObject, pasándole un converter que va a indicar al serializador como deben serializarse las fechas.

Trabajar con fechas y JSON representa un problema, que básicamente se resume en que la especificación de JSON no define un formato de fecha. La librería JSON.NET nos permite modificar como se serializan las fechas a través de esta sobrecarga y un conjunto de convertidores (clases derivadas de DateTimeConverterBase). Si queremos saber mas sobre este problema recomiendo el siguiente enlace :http://james.newtonking.com/archive/2009/02/20/good-date-times-with-json-net.aspx del propio James Newton-King (autor de JSON.NET)

Personalmente opino que  siempre que sea posible, deberíamos enviar el dato como texto al navegador ¿porque? por simplicidad (principio KISS). Bueno, dicho esto creamos un converter especifico para nuestras intenciones, permitimos modificar el formato de salida a través de un objeto CultureInfo. Al igual que hicimos con Persona,crearemos las clase sobre App_Code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Newtonsoft.Json.Converters;
using System.Globalization;


public class CultureDateTimeConverter : DateTimeConverterBase
{
    CultureInfo _culture = null;
    public CultureDateTimeConverter(CultureInfo culture)
    {
        _culture = culture;
    }


    public override object ReadJson
(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw new NotImplementedException(); } public override void WriteJson
(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { string dateStringValue=""; if (value is DateTime) { DateTime dateTime = (DateTime)value; DateTime utcDateTime = dateTime.ToUniversalTime(); dateStringValue = dateTime.ToString(_culture); } else { if (value is DateTimeOffset) { DateTimeOffset dateTimeOffset = (DateTimeOffset)value; DateTimeOffset utcDateTimeOffset = dateTimeOffset.ToUniversalTime(); dateStringValue = dateTimeOffset.ToString(_culture); } throw new Exception("Expected date object value."); } writer.WriteValue(dateStringValue ); } }

Dejamos el método ReadJson como no implementado, ya que no lo necesitamos (¿segregación de interfaces?si).

Bien, ahora que ya tenemos todos los elementos solo nos falta la página.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Home.aspx.cs" Inherits="Home" %>

<!DOCTYPE html >
<html>
<head runat="server">
    <title></title>
    <style type="text/css">
        .hidden
        {
            display: none;
        }
    </style>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/tempo.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var url = '<%:VirtualPathUtility.ToAbsolute("~/Handlers/PersonasDataHandler.ashx") %>';
            $.getJSON(url, function (jsonData) {
                Tempo.prepare("template").render(jsonData);
                $("#template").removeClass("hidden");
            });
        });
    
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <ol id="template" class="hidden">
            <li data-template>
                <h3>
                    {{Id}}</h3>
                <p>
                    {{Nombre}}, {{Apellidos|truncate 25}}</p>
                <p>
                    nacido el {{FechaNacimiento}}</p>
            </li>
            <li data-template-fallback>
            Error, Javascript necesario para visualizar la página!</li>
        </ol>
    </div>
    </form>
</body>
</html>

La página es muy sencilla, y sin duda el elemento mas interesante es el template de Tempo.js. En realidad se trata de HTML normal, en el que insertamos marcas que el motor de renderizado identifica - http://tempojs.com/#html - y que va a sustituir los datos obtenidos del servidor.

<ol id="template" class="hidden">
    <li data-template>
        <h3>
            {{Id}}</h3>
        <p>
            {{Nombre}}, {{Apellidos|truncate 25}}</p>
        <p>
            nacido el {{FechaNacimiento}}</p>
    </li>
    <li data-template-fallback>
    Error, Javascript necesario para visualizar la página!</li>
</ol>

Fijémonos en la marca de {{Apellidos}}, posee un marcado especial truncate que le indica que debe truncar el dato cuando este exceda de 25 posiciones. Tempo.js posee un buen número de marcadores y filtros que nos van a permitir formatear nuestros datos cómodamente – http://tempojs.com/#filter-functions

Tempo.js también nos permite anidar plantillar, plantillar condicionales,  definir platillas de error para cuando el navegador no dispone de soporte para JavaScript … os recomiendo que echéis un vistazo a la web para que veáis la lista completa de funcionalidades. http://tempojs.com/

Bien, pues solo nos falta comentar el script de inicialización de página, en el que activamos Tempo.js y vamos al servidor para obtener los datos en formato JSON.

<script type="text/javascript">
    $(document).ready(function () {
        var url = '<%:VirtualPathUtility.ToAbsolute("~/Handlers/PersonasDataHandler.ashx") %>';
        $.getJSON(url, function (jsonData) {
            Tempo.prepare("template").render(jsonData);
            $("#template").removeClass("hidden");
        });
    });    
</script>

Activar Tempo.js es muy sencillo, solo debemos llamar al método prepare y posteriormente renderizar los datos.

Tempo.prepare("template").render(jsonData);

El programa en ejecucion queda de la siguiente forma … Bonito lo que se dice bonito no lo hemos hecho … pero …

image
Como ya hicimos en el post anterior hemos subido el código a SkyDrive para que podáis descargarlo. Este es el enlace: https://skydrive.live.com/#cid=20A9C248301397B3&id=20A9C248301397B3%21143


Finalmente solo decir que Tempo.js no es la única librería de este tipo que existe, pero si me ha parecido muy fácil de utilizar, por lo que os invito a utilizar los comentarios para contar vuestras experiencias con otras librerías de este estilo.

Saludos,

DJK!

Pedro  Herrarte  Sánchez
Tempo.js, motor de renderización de plantillas HTML con JSON. Ejemplo con ASP.NET
Pedro Herrarte Sánchez

Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación. Posee mas de diez años de experiencia trabajando para las principales empresas de España. Es especialista en tecnologías .NET, entornos Web (ASP.NET, ASP.NET MVC,jQuery, HTML5), bases de datos (SQL Server y ORACLE) e integración de sistemas. Es experto en desarrollo (C#, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE). Pedro es MCP y MAP 2012, es fundador, diseñador y programador de www.devjoker.com..
Fecha de alta:22/02/2012
Última actualizacion:22/02/2012
Visitas totales:5882
Valorar el contenido:
Últimas consultas realizadas en los foros
Últimas preguntas sin contestar en los foros de devjoker.com