Una sinfonía en C#

Un pequeño aporte a la comunidad de habla hispana.

Templates con WinJS

Cuando queremos representar datos en nuestras páginas a partir de un template que se repite, lo más recomendable es utilizar un motor de templates como JsRender o JsViews, la pregunta es qué alternativas tenemos en WinJS?

Motor de templates integrado en WinJS

Ya existe un tipo definido para manejar templates dentro de WinJS

new WinJS.Binding.Template();

con él podemos indicar a un ListView cómo renderizar cada ítem, y también podemos generar nuestros templates y utilizarlos sobre un elemento del DOM.

Primer crear el template en HTML

Vamos a crear un proyecto metro en blanco y modificar el HTML por defecto para que se vea así:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Application16</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>

    <!-- Application16 references -->
    <link href="/css/default.css" rel="stylesheet">
    <script src="/js/default.js"></script>
</head>
<body>
<p>
    <div id="template">
        <span data-win-bind="innerText:valor"></span>
    </div>
</p>
    <div id="container"></div>
</body>
</html

La idea es sencilla, utilizar el div con id template como template y renderizarlo dentro del div con id container

Antes que eso vamos a correr la aplicación y ver qué pasa

image

Nada, vemos la pantalla en negro, cosa que en principio está bien, pero vamos a ver el DOM Explorer a ver qué es lo que realmente tiene el navegador en memoria

image

image

Vemos que el div template se está renderizando cosa que no es deseable, sin embargo no nos preocupamos, vamos a default.js y hacemos una pequeña modificación para decirle a WinJS que ese elemento debe ser tratado como un template.

(function () {
    "use strict";

    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
                        WinJS.UI.processAll().then(function () {

                            //recuperamos el elemento del DOM
                            var templateElement = document.querySelector("#template");
                            //creamos un template a partir del elemento recuperado
                            var template = new WinJS.Binding.Template(templateElement);

                        });
    };

    app.start();
})();

Simplemente recuperamos el elemento del DOM y creamos un objeto del tipo WinJS.Binding.Template a partir de él, corremos la aplicación y vemos el DOM Explorer nuevamente

image

Vemos que WinJS agregó al elemento que definimos como template “display: none” para que no se vea en la página, entonces primer tema solucionado.

Renderizando datos a partir del tempalte

Ahora vamos a crear un set de datos y utilizar el template recién definido

(function () {
    "use strict";
    //creamos un objeto con una propiedad
    var data = {valor:"primer valor del set de datos"};

    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
                        WinJS.UI.processAll().then(function () {

                            //recuperamos el elemento del DOM
                            var templateElement = document.querySelector("#template");
                            //creamos un template a partir del elemento recuperado
                            var template = new WinJS.Binding.Template(templateElement);
                            //recuperamos el elemento sobre el cual vamos a renderizar los datos
                            var target = document.querySelector("#container");
                            //renderizamos los datos sobre el destino
                            template.render(data, target);
                        });
    };

    app.start();
})();

creamos una variable en la que colocamos un objeto que será nuestro origen de datos, luego utlizamos la función render del template para utlizar esos datos y renderizar el resultado sobre el destino.

image

Perfecto, qué pasa si queremos renderizar un array de datos, entonces tenermos que usar un bucle del siguiente modo:

(function () {
    "use strict";
    //creamos un objeto con una propiedad
    var data = [{ valor: "primer valor del set de datos" }, { valor: "segundo valor del set de datos" }, { valor: "tercer valor del set de datos" }];

    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
                        WinJS.UI.processAll().then(function () {

                            //recuperamos el elemento del DOM
                            var templateElement = document.querySelector("#template");
                            //creamos un template a partir del elemento recuperado
                            var template = new WinJS.Binding.Template(templateElement);
                            //recuperamos el elemento sobre el cual vamos a renderizar los datos
                            var target = document.querySelector("#container");

                            //renderizamos los datos sobre el destino
                            for (var i = 0; i < data.length; i++) {
                                template.render(data[i], target);
                            }                                                       
                        });
    };

    app.start();
})();

y con eso solucionamos el problema, o podemos utilizar la función foreach que agrega WinJS a los array, del siguiente modo:

(function () {
    "use strict";
    //creamos un objeto con una propiedad
    var data = [{ valor: "primer valor del set de datos" }, { valor: "segundo valor del set de datos" }, { valor: "tercer valor del set de datos" }];

    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
                        WinJS.UI.processAll().then(function () {

                            //recuperamos el elemento del DOM
                            var templateElement = document.querySelector("#template");
                            //creamos un template a partir del elemento recuperado
                            var template = new WinJS.Binding.Template(templateElement);
                            //recuperamos el elemento sobre el cual vamos a renderizar los datos
                            var target = document.querySelector("#container");

                            //renderizamos los datos sobre el destino
                            data.forEach(function (item) {
                                template.render(item, target);
                            });
                        });
    };

    app.start();
})();

y listo:

image

Utilizando templates remotos

Una opción interesante es la capacidad de poder utilizar un template procedente de otro archivo, esto es bien sencillo, creamos un nuevo archivo template.html y colocamos todo el contenido de nuestro template dentro.

<div id="template">
    <p>
        <span data-win-bind="innerText:valor" ></span>
    </p>
</div>

y modificamos el código javascript para utilizar el template externo

(function () {
    "use strict";
    //creamos un objeto con una propiedad
    var data = [{ valor: "primer valor del set de datos" }, { valor: "segundo valor del set de datos" }];

    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
                        WinJS.UI.processAll().then(function () {

                            //recuperamos el elemento del DOM
                            var templateElement = document.querySelector("#template");
                            //creamos un template a partir del archio remoto
                            var template = new WinJS.Binding.Template(null, { href: "/html/template.html" });

                            //recuperamos el elemento sobre el cual vamos a renderizar los datos
                            var target = document.querySelector("#container");

                            //renderizamos los datos sobre el destino
                            data.forEach(function (item) {
                                template.render(item, target);
                            });
                        });
    };

    app.start();
})();

simplemente cuando creamos el objeto template le indicamos el parámetro href apuntando al archivo externo, el resto es igual.

Hasta la próxima.

Loading