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.

Cómo tener intellisense de WinJS en módulos Javascript?

Una buena costumbre al desarrollar aplicaciones metro con Javascript es tener nuestro código en módulos separados utilizando funciones autoejecutables y así tener un scope acotado.

Existe un pequeño problema, al ser un archivo separado no tenemos intellisense de las librerías de WinJS (ni de ningúna otra), algo así:

image

Este problema se incrementa ya que no tenemos referencias físicas en el proyecto de los archivos base de WinJS, sino que accedemos a ellos a través de un path especial

image

Sin embargo podemos hacer algo para tener intellisense del WinJS en nuestro módulo del siguiente modo:

image

Simplemente agregamos los tags reference con el atributo path apuntando a los path especiales de las librerías de WinJS y tenemos intellisense.

Hasta la próxima.

Charla a través de Internet sobre Aplicaciones Metro con Javascript

UPDATE 2012.04.12
Se aplazó la VAN para el Viernes 27 de Abril a las 18:00hs GMT

Windows 8 logo

Una vez más voy a tener la suerte de participar de una VAN (Virtual Alt.Net), para la comunidad de Alt.Net Hispano, en esta oportunidad será sobre Aplicaciones Metro con Javascript.

VW Camper

El tema

La idea hablar de Windows 8 y las aplicaciones metro, comenzando con un poco de teoría sobre la plataforma y qué son y cuáles los lineamientos de las aplicaciones Metro.

Vamos a tratar de ir contando un poco el modelo de programación y cómo nos ayuda WinJS para todo esto

No voy a estar sólo

En la VAN me va a acompañar Rubén Altman del equipo de Kinetica y tal vez algunas sorpresas.

La fecha

Será el viernes 13 de Abril a las 18hs GMT, las 15hs de Argentina.

Cómo asistir?

Para participar de la VAN es necesario tener instalado Microsoft Office Live Meeting 2007 client

El Link de acceso es acá

Pueden dejar comentarios e inquietudes en la lista de correo

Para más información acerca de las VAN pueden acceder acá

Entonces, hecha la invitación nos vemos el 13.

Leonardo.

Taller sobre MVC3 en Buenos Aires

mvc_DesignPattern

Durante las primeras semanas de Abril estaré en el Grupo de Usuarios de Microsoft dando un nuevo taller sobre MVC, en este caso actualizado a la versión 3 y hablando un poco sobre las novedades de MVC 4.

Contenido

Por supuesto que debido a la cantidad de temas y la duración del taller el nivel será introductorio, la idea es dar un repaso sobre los conceptos más sobresalientes y no dejar de nombrar algunos detalles de implementación en situaciones reales, el temario será el siguiente:

Introducción a MVC

  • Teoría
  • Separación de conceptos
  • Escalabilidad
  • Implementaciones: ASP.NET MVC, Monorail.
  • Diferencias entre MVC y WebForms / ASP clásico
  • Colaboración
  • Legibilidad
  • Testeo
  • Por qué necesitamos MVC?

Ruteo

  • Modelos de ruteo
  • SEO
  • Indización de buscadores
  • Configuración personalizada
  • Áreas

El modelo

  • Responsabilidad del modelo
  • Separación
  • Testeo

El controlador

  • Responsabilidades
  • Action Filters
  • Model Binders
  • ActionResult
  • FileResult
  • JSONResult
  • JavaScriptResult

La vista

  • Responsabilidad
  • Motores de renderización
    • ASP.NET
    • Razor
  • HTMLHelpers
  • ViewData
  • Vistas tipadas
  • Validaciones
  • Testeo

Aspectos avanzados

  • Ajax
  • jQuery y MVC
  • MVC 4
  • Mejoras en Razor
  • ASP.NET Web API

El taller se desarrollará íntegramente con PC para cada asistente para poder experimentar con los conceptos que vamos repasando.

Fechas y duración

Serán cuatro encuentros:

  • Lunes 16 de Abril de 2012
  • Martes 17
  • Lunes 23
  • Martes 24

el horarios será de 18:00 a 22:00 hs. El lugar es en Rivadavia 1479 - Piso 1 - Oficina A 
Ciudad Autónoma de Bs.As.

Registración

Dejo el link para registrarse, el cupo es limitado y es con costo.

Nos vemos, Leonardo.

Namespaces en aplicaciones Metro Javascript con la ayuda de WinJS

En el post anterior sobre Metro vimos cómo se puede hacer para “bindear” el modelo a la vista, existe una particularidad en el ejemplo que pasó casi inadvertida y tiene que ver con la forma de organizar las aplicaciones Metro Javascript.

El patrón module en Javascript

En este post vimos cómo se pueden utilizar funciones auto-ejecutable para tener un ámbito de visibilidad limitado y que nuestro código no interfiera con el resto de la aplicación, la utilización de esta técnica se conoce como el patrón module.

El inconveniente de utilizarlo es que lo que definamos dentro de la función no podrás ser visto desde afuera, es por eso que yo definí el modelo como una propiedad del objeto document el cual es visible globalmente, sin embargo, existe una alternativa a esto.

Namespaces en Metro

Podemos crear un objeto global y generar un espacio de nombres y allí poner los orígenes de datos, ya vimos cómo podemos hacerlo, sin embargo WinJS ya trae consigo un mecanismo para crear espacios de nombre.

La idea es definir dentro de un módulo nuestro origen de datos pero dentro de un espacio de nombres que pueda ser visto globalmente para poder referenciarlo desde la vista con su nombre completo y el WinJS se ocupe del binding. Entonces manos a la obra>

Un ejemplo vale más de mil palabras

Creamos una nueva aplicación Metro de Javascript y vamos directo al archivo default.js

// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
    "use strict";

    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
        if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
            if (eventObject.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize 
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension. 
                // Restore application state here.
            }
            WinJS.UI.processAll();
        }
    };

    app.oncheckpoint = function (eventObject) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the 
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // eventObject.setPromise(). 
    };

    app.start();
})();

Inicialmente tenemos esto, vamos a generar un origen de datos y colocarlo como propiedad del objeto document

(function () {
    "use strict";
    //creamos el origen de datos
    var dataSource = { nombre: 'leonardo', apellido: 'micheloni' };
    //lo asignamos como una propiedad del document para tener visibilidad fuera de
    //este módulo
    document.dataSource = dataSource;

    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
        //le decimos a WinJS que ejecute los binding
        WinJS.Binding.processAll();
    };

    app.start();
})();

Modificamos el HTML

<!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>
    <div data-win-bindsource="document.dataSource">
        <p data-win-bind="innerText: nombre"></p>
        <p  data-win-bind="innerText: apellido"></p>
    </div>
</body>
</html>

y funciona muy bien

image

Utilizando la función namespace de WinJS

Ahora, vamos a poner nuestro origen de datos dentro de otro archivo js y agregarlo a un namespace y luego referenciarlo desde la vista

default.js

(function () {
    "use strict";
    var app = WinJS.Application;

    app.onactivated = function (eventObject) {
        //le decimos a WinJS que ejecute los binding
        WinJS.Binding.processAll();
    };
    
    app.start();
})();

data.js

(function () {
    'use strict';
    //creamos el origen de datos
    var dataSource = { nombre: 'leonardo', apellido: 'micheloni' };
    //definimos el namespace "datos" y colocamos nuestro origen dentro
    WinJS.Namespace.define("datos", dataSource);
})();

default.html

<!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>

    <link href="/css/default.css" rel="stylesheet">
    <script src="/js/default.js"></script>
    <!-- referenciamos el archivo donde definimos nuestro origen de datos-->
    <script src="/js/data.js"></script>
</head>
<body>
    <div data-win-bindsource="document.dataSource">
        <p data-win-bind="innerText: nombre"></p>
        <p  data-win-bind="innerText: apellido"></p>
    </div>
</body>
</html>

y el resultado es igual al anterior

image

De más está decir que son pocas las situaciones en la cuales no deberíamos colocar nuestro código en un módulo separado y referenciarlo utilizando namespaces.

Hasta la próxima, Leonardo.