lunes, 19 de noviembre de 2012

Explorando Knockout

Hola.

Hoy vamos a hablar de knockout otro framework de javascript del cual últimamente se ha oído hablar bastante.
Básicamente knockout es un framework que implementa el patrón MVVM  (Model-View-View-Model). En este patrón disponemos de un modelo que se ajusta a la vista. Knockout lo que hace es enlazar el modelo de la vista de forma bidireccional, con lo que cualquier cambio en la vista se refleja automáticamente en el modelo y cualquier cambio en el modelo se refleja automáticamente en la vista.
Vamos a ver un ejemplo.
Crearemos un proyecto de Visual Studio (proyecto Aplicación ASP.NET vacia por ejemplo).
Una vez creado el proyecto, agregamos un nuevo  WebForm.
Antes de ponernos a programar en el form, vamos a agregar a nuestro proyectos las librerías de javascript que vamos a necesitar (básicamente jquery y knockout). Para ello yo me he decantado por agregarlas a través de NuGet (vosotros podéis agregarlas manualmente si lo preferís).

Ahora que ya tenemos en nuestro proyecto las librerías que vamos a necesitar es hora de empezar a programar nuestro WebForm.
Primero agregaremos los enlaces a las librerías:
<head runat="server">
    <title></title>
    <script type="text/javascript" src="Scripts/jquery-1.8.2.min.js"></script>
    <script type="text/javascript" src="Scripts/knockout-2.2.0.js"></script>
</head>
Lo siguiente que vamos a hacer es crear un formulario para introducir los datos de un usuario:
        <table>
            <tr><td>ID:</td><td><label id="lb_id" /></td></tr>
            <tr><td>Nombre:</td><td><input type="text" /></td></tr>
            <tr><td>1er Apellido</td><td><input type="text" /></td></tr>
            <tr><td>2o Apellido</td><td><input type="text" /></td></tr>
            <tr><td></td><td><label id="lb_message" /></td></tr>
            <tr>
                <td></td>
                <td>
                    <button >Guardar</button>
                </td>
            </tr>
        </table>
Hasta ahora no ha tenido excesiva complejidad.
Vamos a empezar a crear nuestro modelo de objetos que se va a enlazar con los controles del formulario. Para ello agregamos el siguientes script después del formulario. Es importante que este situado después de los tags del formulario.
    <script type="text/javascript">
        var usuario = {
            ID: ko.observable(-1),
            Nombre: ko.observable("John"),
            Apellido1: ko.observable("Doe"),
            Apellido2: ko.observable("No name"),
            Message: ko.observable(),
        };
        ko.applyBindings(usuario);
    </script>
Que es lo que hemos hecho? Bueno, hemos creado una variable “usuario”, a la cual le hemos definido los siguientes atributos (ID, Nombre, Apellido1, Apellido2).
Además de definir estos atributos, hemos definido dichos atributos como observables por knockout (ko.observable), y los hemos inicializado con unos valores por defecto.
Por ahora hemos definido las propiedades del objeto, pero aun no la hemos enlazado con ningún campo del formulario. Como realizamos esto. Agregando a los controles del form la propiedad “data-bind”.
Así pues modificamos nuestro formulario para que contenga dichas propiedades:
        <table>
            <tr><td>ID:</td><td><label id="lb_id" data-bind="text: ID" /></td></tr>
            <tr><td>Nombre:</td><td><input type="text" data-bind="value: Nombre" /></td></tr>
            <tr><td>1er Apellido</td><td><input type="text" data-bind="value: Apellido1" /></td></tr>
            <tr><td>2o Apellido</td><td><input type="text" data-bind="value: Apellido2" /></td></tr>
            <tr><td></td><td><label id="lb_message" data-bind="text: Message" /></td></tr>
            <tr>
                <td></td>
                <td>
                    <button>Guardar</button>
                </td>
            </tr>
        </table>
Como podemos ver los inputs los estamos enlazando con las propiedad de la variable usuario por medio de “data-bind=’value: XXXXXX’ “, mientras que el campo label lo estamos enlazando por medio de la propiedad “data-bind=’text:XXXXX’ “.
Con Knockout no solo podemos enlazar propiedades, también podemos enlazar eventos. Ya que knockout nos brinda dicha posibilidad, vamos a enlazar el evento “click” con un método de la variable usuario, el cual se encargará de guardar los datos del usuario.
Lo primero que vamos a hacer es modificar el objeto usuario para crear el método “Guardar”:
    <script type="text/javascript">
        var usuario = {
            ID: ko.observable(-1),
            Nombre: ko.observable("John"),
            Apellido1: ko.observable("Doe"),
            Apellido2: ko.observable("No name"),
            Message: ko.observable(),
            Guardar: function guardar_usuario() {
                var json = ko.toJSON(usuario);
                $.ajax({
                    url: "/Usuarios.aspx/SaveUsuario",
                    type: "POST",
                    data: json,
                    contentType: "application/json",
                    success: function (result) {
                        usuario.ID(result.d.ID);
                        usuario.Nombre(result.d.Nombre);
                        usuario.Apellido1(result.d.Apellido1);
                        usuario.Apellido1(result.d.Apellido1);
                        usuario.Message(result.d.Message);
                    }
                });
            }
        };
        ko.applyBindings(usuario);
    </script>
Como podemos ver el método “guardar_usuario” realizará una llamada Ajax y actualizará los valores de usuario con el resultado de dicha llamada.
Ahora vamos a modificar el botón Guardar para enlazarlo con este método que hemos creado. Modificamos el form con el siguiente código:
        <table>
            <tr><td>ID:</td><td><label id="lb_id" data-bind="text: ID" /></td></tr>
            <tr><td>Nombre:</td><td><input type="text" data-bind="value: Nombre" /></td></tr>
            <tr><td>1er Apellido</td><td><input type="text" data-bind="value: Apellido1" /></td></tr>
            <tr><td>2o Apellido</td><td><input type="text" data-bind="value: Apellido2" /></td></tr>
            <tr><td></td><td><label id="lb_message" data-bind="text: Message" /></td></tr>
            <tr>
                <td></td>
                <td>
                    <button data-bind="click: Guardar">Guardar</button>
                </td>
            </tr>
        </table>
En este caso el binding lo hemos realizado agregando el atributo “data-bind=’click: XXXXX’ “.
Antes de probar el formulario hemos de crear en la parte de servidor el método que va a ser invocado por medio de la llamada Ajax. Así pues modificamos el code behind de nuestro form y agregamos el siguiente método:
        [WebMethod, ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public static DTO_User SaveUsuario(int ID, string Nombre, string Apellido1, string Apellido2)
        {
            DTO_User usuario = new DTO_User() { ID = ID, Nombre = Nombre, Apellido1 = Apellido1, Apellido2 = Apellido2 };
            //Vamos a suponer que este guarda en BD y que genera un ID 1234
            usuario.ID = 1234;
            usuario.Message = "Usuario Guardado con id:" + usuario.ID + ".";
            return usuario;
        }
Como vemos en el código, estamos usando una clase “DTO_User” para gestionar los datos del usuario. Esta clase no tiene mayor complejidad:
    public class DTO_User
    {
        public int ID { set; get; }
        public string Nombre { set; get; }
        public string Apellido1 { set; get; }
        public string Apellido2 { set; get; }
        public string Message { set; get; }
    }
 Con todo esto, nuestro proyecto ya debería estar listo para ser testeado.
Al ejecutarlo se nos tiene que mostrar el formulario que hemos definido:

Cambiamos uno de los campos del formulario:

Antes de comprobar el resultado pulsando el botón de “Guardar”, vamos a poner un breakpoint en el método de code behind de nuestro WebForm para comprobar que valores nos llegan como parámetros. Una vez puesto el breackpoint podemos ejecutar a ver que pasa:

Como podemos ver, sin que hayamos modificado la variable usuario, a nuestro método “SaveUsuario” ya nos llega el Nombre que hemos modificado en el formulario.
Pulsamos F5 para continuar y poder ver como queda el formulario tras la ejecución del método:

Vemos que tras la ejecución, el cambio de ID y Descripción en la variable usuario se refleja automáticamente en los campos del formulario.

Bueno, hasta aquí esta primera prueba de Knockout.

Podéis bajaros el proyecto de ejemplo del siguiente enlace:

Espero que os sea útil.