Mostrando entradas con la etiqueta javascript. Mostrar todas las entradas
Mostrando entradas con la etiqueta javascript. Mostrar todas las entradas

viernes, 15 de febrero de 2013

HTML5: Introducción a los Web Workers 2

En la entrada anterior vimos una introducción a los web workers. En ella vimos como crearlos y como comunicarnos desde la página web con el web worker y viceversa. Pese a que con lo visto puede ser más que suficiente en muchísimos casos se nos quedaron algunas cosas en el aire y que veremos a continuación.

Gestión de errores
Puede que para algunos procesos simples no nos tengamos que preocupar de la gestión de errores (aunque creo que nunca está de más), pero en otras ocasiones puede que se imprescindible. Para comunicar un error desde nuestro worker usaremos el evento error, así que lo que haremos será suscribirnos al evento error del worker desde nuestra página web.
worker.addEventListener('error', _error, false);

function _error(e) {
    var output = document.querySelector('#output');
    output.innerHTML = 'ERROR: Line ' + e.lineno + ' in ' + e.filename + ': ' + e.message;
}
Y en el worker usaremos el siguiente código para simular un error (lanzaremos un error en caso que el número pasado sea cero)
// Procesamos el mensaje recibido
function _message(e) {
    // Simulamos un error
    if (e.data == 0)
        throw new Error(0, "Por favor, introduce un número mayor o igual a uno");

    var primes = _getPrimes(e.data);
    self.postMessage(primes);
}
Detener el web worker
En el caso que queramos detener un worker, lo podemos hacer de dos maneras. La primera de ellas desde el código del propio worker. En ese caso debemos usar el método close. Para probar esté método pondremos el siguiente código en el método _message de nuestro worker (finalizamos la ejecución del worker en caso que intentemos calcular los números primos de un número negativo).
// Simulamos la detención del worker
if (e.data < 0) 
    self.close();    
En caso que queramos acabar con el worker desde la página web debemos usar el método terminate. En nuestro ejemplo usaremos un botón para detener la ejecución del worker
<input type="button" id="btnTerminate" value="Terminar" onclick="_terminate()"/>
Y este es el código del método onclick
function _terminate() {
    worker.terminate();
}
Y con esto acabamos la introducción básica a los web workers. Espero que les sea de utilidad.

Happy coding!

jueves, 7 de febrero de 2013

HTML5: Introducción a los Web Workers 1


Uno de los mayores inconvenientes que tiene javascript como lenguaje de programación es que es un entorno de subproceso único. Esto implica que en procesos largos y costosos podemos dejar "congelado" el navegador del cliente.
Supongamos la siguiente página
<input id="txtValue" type="text" /><input id="btnProcess" onclick="_process()" type="button" value="Calculate primes" /><div id="output">
Y el siguiente código en javascript
function _process() {
    var value = document.querySelector('#txtValue').value;
    var primes = getPrimes(value);

    var output = document.querySelector('#output');
    output.innerHTML = primes.toString();
}

// Devuelve un array con los números primos comprendidos entre 1 y value.
function getPrimes(value) {
    var primes = [];
            
    for (var i = 1; i <= value; i++) {
        if (_isPrime(i))
            primes.push(i);                
    }

    return primes;
}

// Devuelve true si un número es primo, false en otro caso.
function isPrime(n) {
    if (n < 2) return false;
    var m = Math.sqrt(n);
    for (var i = 2; i <= m; i++)
        if (n % i == 0) return false;
    return true;
}
Si ponemos un valor elevado, por ejemplo un millón, vemos que durante un par de segundos nuestra página deja de responder.

Los Web Workers aparecen con la especificación de HTML5 y se definen como un script que se ejecuta en background independientemente de otros scripts y sin que afecte al rendimiento de la página.

Modificar el comportamiento del ejemplo anterior para que se ejecute en un Web Worker es bastante sencillo. La forma más fácil de hacer es aislar el código de nuestro Web Worker en un fichero y crear a partir de él nuestro objeto Worker. Para hacer esto haremos lo siguiente en nuestra página web
var worker = new Worker('webworker.js');
worker.addEventListener('message', _message, false);

function _message(e) {
    var output = document.querySelector('#output');
    output.innerHTML = e.data.toString();
}
En la primera linea creamos nuestro Worker a partir del código que tengamos en el fichero webworker.js, y en la segunda linea nos "enganchamos" al evento message del Worker, ya que a través de este evento es como se comunicará nuestro Worker con nosotros (la página web). Sólo nos falta saber como nos comunicaremos con nuestro Worker. Esto también es bastante sencillo y lo haremos de la siguiente manera
function _process() {           
    var value = document.querySelector('#txtValue').value;
    worker.postMessage(value);
}
Este método será llamado cada vez que pulsemos el botón "Calculate primes". En el extraemos el valor que queremos procesar y lo pasamos como parámetro en el método postMessage. Este método es la forma que tenemos de comunicarnos con el Worker.

Construir el Worker también es bastante fácil y en él se aplican los mismo métodos y eventos que hemos comentado anteriormente. El Worker recibe la información de la página a través del evento message y se comunicará con la página a través del método postMessage. Sabiendo esto el código del Worker quedaría de la siguiente forma
addEventListener('message', _message, false);

// Procesamos el mensaje recibido
function _message(e) {
    var primes = _getPrimes(e.data);
    self.postMessage(primes);
}

// Devuelve un array con los números primos comprendidos entre 1 y value.
function _getPrimes(value) {
    var primes = [];

    for (var i = 1; i <= value; i++) {
        if (_isPrime(i))
            primes.push(i);
    }

    return primes;
}

// Devuelve true si un número es primo, false en otro caso.
function _isPrime(n) {
    if (n < 2) return false;
    var m = Math.sqrt(n);
    for (var i = 2; i <= m; i++)
        if (n % i == 0) return false;
    return true;
}
Si ejecutamos este código con valores elevados, vemos que nuestra página no sufre ningún tipo de efecto secundario mejorando considerablemente la experiencia del usuario en la misma.

Otra cuestion a tener en cuenta en los Web Workers es a que tienen y a que no tienen acceso (por cuestiones de seguridad). Bien, los Web Wokers puede acceder a
  • Objeto navigator
  • Objeto location (de solo lectura)
  • XMLHttpRequest
  • setTimeout()/clearTimeout() y setInterval()/clearInterval()
  • Caché de la aplicación
  • Importación de secuencias de comandos externas a través del método importScripts()
  • Generación de otros Web Workers
Y no pueden acceder
  • DOM (no es seguro para el subproceso)
  • Objeto window
  • Objeto document
  • Objeto parent
Respecto a los navegadores compatibles, con IE solo podremos usar esta característica de HTML5 a partir de la versión 10. Para el resto de navegadores lo mejor es mirar en esta página.

Más información en la página de w3schools 

EDIT: Por recomendación @ydarias, añado la página de Mozilla sobre el uso de los web workers como lectura recomendada.

También se puede bajar el ejemplo que hemos comentado desde aquí.

Happy coding!

martes, 27 de noviembre de 2012

Limpiar un input file con jQuery

Hace bastante tiempo que no escribo nada porque ando bastante liado, pero me ha parecido bastante interesante compartir esto. El problema surge cuando tras subir un fichero a nuestro servidor queremos limpiar el contenido de nuestro input file desde cliente (por ejemplo, con jQuery). La primera aproximación podría ser esta
$('#fileupload').attr({ value: '' });
Si hemos trabajado algo con web sabemos que esta opción no es válida porque por motivos de seguridad el control es de solo lectura y no podemos modificar su contenido. La solución pasa por volver a crear el control usando el método clone de jQuery.
$fileupload = $('#fileupload');
$fileupload.replaceWith($fileupload.clone(true));
El método clone admite dos parámetros que nos permitirá conservar los valores y los manejadores de los eventos que tengamos definidos en nuestro control o controles hijos.

Espero que les sea útil. Happy coding!

jueves, 30 de agosto de 2012

Haciendo test en javascript con jasmine

Antes de irme de vacaciones asistí a unas charlas denominadas #jsweek dadas por el grupo @agileCanarias. La charlas fueron impartidas por @ydarias y por @axelhzf, y se tocaron temas tan divertidos como los WTF de javascript, CoffeeScript y Backbone.

Bien, en la charla de introducción a javascript aprendí a usar jasmine, que no es otra cosa que un framework para hacer test unitarios en javascript. A medida que escribíamos los test para la kata fizzbuzz me di cuenta que podría aplicar este framework a mi método de comparación de objetos que expliqué en mi anterior post (Comparando objetos en javascript)

Sin ser un experto, o más bien, considerándome un neófito en esto de los test unitarios, lo primero que debemos hacer es bajarnos el framework desde su página web. Una vez descargado y descomprimido veremos que tenemos la siguiente estructura
  • Un fichero SpecRunner.html desde donde se ejecutaran los test que definamos.
  • Una carpeta lib donde esta el propio framework y donde en principio no tenemos que tocar nada.
  • Una carpeta spec donde irán los test que queremos ejecutar.
  • Una carpeta src donde irá el código que queremos probrar.
En mi caso he creado un proyecto llamado HelperJS con un fichero prototypes.js donde está el código descrito en el post anterior y una carpeta test que tiene la estructura anteriormente descrita. Ahora lo que haremos será abrir el fichero SpectRunner.html y añadiremos las referencias a los ficheros de test y ded código que queremos probar.
<!-- include spec files here... -->
<script type="text/javascript" src="spec/prototypesSpec.js"></script>

<!-- include source files here... -->
<script type="text/javascript" src="../prototypes.js"></script>
Si abrimos la página SpecRunner.html en el navegador obtendremos una página vacia, por lo que lo siguiente será escribir los test en el fichero prototypesSpec.js. Siguiendo un poco la métodología TDD (y repito que soy un novato total en el tema) lo normal es escribir los test de lo más simple a lo más complejo (aunque en mi caso el código ya está escrito). Basándome en esto lo más simple es escribir un test para cuando el segundo objeto es null o undefined. Con esto podemos escribir nuestro primeros test de la siguiente manera
describe("Object.prototype.equals", function() {
 it("El objeto a comparar es null", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = null;

  expect(u1.equals(u2)).toBe(false);
 });

 it("El objeto a comparar es undefined", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = undefined;

  expect(u1.equals(u2)).toBe(false);
 });
});
Como vemos el código es bastante fácil de entender. El método describe se usar para definir un grupo de test (u otro grupo) y le pasamos una función donde se definen los test. Para definir un test usamos el método it, al que le pasamos una descripción del test y un función donde se ejecuta el test gracias a expect donde indicamos lo que queremos probar y el valor que debe tener. Si todo ha ido bien al recargar la página SpecRunner.html debemos obtener algo como esto


Con esto claro, ya podemos escribir el resto de test en lo que comprobamos distintas posibilidades que se pueden dar.
describe("Object.prototype.equals", function() {
 it("El objeto a comparar es null", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = null;

  expect(u1.equals(u2)).toBe(false);
 });

 it("El objeto a comparar es undefined", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = undefined;

  expect(u1.equals(u2)).toBe(false);
 });

 it("Distinto numero de propiedades", function() {
  var u1= {prop1 : "value1", prop2: 2};  
  var u2= {prop1 : "value1", prop2: 2, prop3: 3};  

  expect(u1.equals(u2)).toBe(false);
 });

 it("Mismas propiedades pero con distintos valores", function() {
  var u1= {prop1 : "value1", prop2: 2};  
  var u2= {prop1 : "value1", prop2: 3};  

  expect(u1.equals(u2)).toBe(false);
 }); 

 it("Mismo numero de propiedades pero con nombres distintos", function() {
  var u1= {prop1 : "value1", prop2: 2};  
  var u2= {prop1 : "value1", prop3: 3};  

  expect(u1.equals(u2)).toBe(false);
 }); 
  
 it("Dos objetos simples iguales", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = {prop1: "1", prop2: 2};

  expect(u1.equals(u2)).toBe(true);
 });

 it("Dos objetos compuestos distintos", function() {
  var u1 = {prop1: "1", prop2: 2, prop3: { prop4: 4}};
  var u2 = {prop1: "1", prop2: 2, prop3: { prop5: 5}};

  expect(u1.equals(u2)).toBe(false);
 });

 it("Dos objetos compuestos iguales", function() {
  var u1 = {prop1: "1", prop2: 2, prop3: { prop4: 4}};
  var u2 = {prop1: "1", prop2: 2, prop3: { prop4: 4}};

  expect(u1.equals(u2)).toBe(true);
 });
});
Obteniendo la siguiente salida


Como vemos es bastante fácil escribir test simples para nuestro código javascript. Si estás interesado en probar otros framework de este tipo también está QUnit que por lo que me han comentado también está bastante bien.

Todo esta código espero subirlo próximamente a GitHub.

Happy coding!

viernes, 10 de agosto de 2012

Comparando objetos en javascript

La verdad es que por muchas horas que invierta en programar en javascript y en leer esos pequeños detalles que tiene y que pueden volverte loco un par de horas no paro de sorprenderme al ver algunas cosas. La última sin ir más lejos es la siguiente y la mostraré con un simple trozo de código.
var u1 = {prop1 : 1, prop2: "value2"};
var u2 = {prop1 : 1, prop2: "value2"};
console.log(u1 == u2); 
console.log(u1 === u2);
Simplemente estamos declarando dos objetos y los estamos comparando. Como vemos ambos objetos tienes las mismas propiedades (prop1 y prop2) y los mismos valores en dichas propiedades, prop1 vale 1 y prop2 vale "value2". Las siguientes lineas muestran por la consola el resultado de comparar ambos objetos. Supongo que la respuesta lógica sería pensar que algunas de las dos comparaciones debería devolver true. ¿Verdad?, pues no, ambas comparaciones devuelve false.

Si el objeto lo declaramos de otra manera menos que el efecto es el mismo
function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;    
}

var u1 = new Foo(1, "value2");
var u2 = new Foo(1, "value2");

console.log(u1 == u2);  // false
console.log(u1 === u2); // false
Vemos que en ese caso el comportamiento similar así que podemos descartar que este comportamiento sea debido a como hemos declarado nuestros objetos.

Después de pensar un poco en el asunto y necesitando una función que me comparara dos objetos busqué la forma de hacer dicha comparación. Lo primero que determiné es que son para mi dos objetos iguales, y para mi negocio son aquellos objetos cuyas propiedades (solo propiedades y no funciones) sean iguales. O sea que esta comparación sería correcta
function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;
    this.bar = function() {
        // do operation
    }        
}

var u1 = new Foo(1, "value2");
var u2 = new Foo(1, "value2");

console.log(u1 == u2);  // false
console.log(u1 === u2); // false
Con eso claro lo único que tenemos que hacer es recorrer las propiedades de los objetos implicados e ir comparando valores. Recorrer las propiedades de un objeto es bastante fácil pero puede darnos algún problema si no tenemos algunas cosas en cuenta. En concreto el principal problema es que dependiendo del contexto donde recorramos las propiedades del objeto podemos obtener las propiedades heredadas de dicho objeto, por lo que para evitarlo debemos usar el método hasOwnProperty, que nos asegura que esa propiedad es del objeto en cuestión. En nuestro ejemplo
function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;
    this.func1 = function() {
        // do operation
    }        
}

var u1 = new Foo(1, "value2");
for (var p in u1)
{
  if (u1.hasOwnProperty(p))
    console.log(p);        
}
Obtendríamos esta salida
prop1
prop2
bar
Con esto claro ya podemos intentar hacer nuestro comparador de objetos. La primera versión que se nos viene a la mente es hacer algo así
function equals(p1, p2)
{
    // Comparamos los objetos
}
Esta alternativa no es mala, pero pienso que es más elegante extender el tipo object y añadir el método equals, para poder hacer algo así
p1.equals(p2);
Esto es bastante fácil en javascript y el esqueleto sería el siguiente
Object.prototype.equals = function(x)
{
  // Comparamos los objetos 
}
Al principio del método podemos hacer algunas comparaciones básicas como si x no está definido o si los objetos a comparar tienen el mismo número de propiedades. Esta útlima comparación se hace a través del método keys que desgraciadamente no está disponible en todos los navegadores (se puede consultar su disponibilidad aquí). Con esto, nuestro método ya va tomando cuerpo y sería de la siguiente forma
Object.prototype.equals = function(x)
{   
    if (x === null || x === undefined) 
      return false;
            
    if (Object.keys(this).length != Object.keys(x).length)
      return false;
       
    // Comparamos los objetos                             

    return true;                
}
Con esto ya lo único que nos queda es recorrer las propiedades del objeto de origen e ir buscando sus homólogas para luego comparar su valor. En estas comparaciones veremos de que tipo es la propiedad, para ver si comparamos directamente sus valores, volvernos a llamar al método equals en caso de ser un objeto o devolvemos false en caso que sea una función. Con esto nuestro método equals quedaría de la siguiente manera
Object.prototype.equals = function(x)
{   
    if (x === null || x === undefined) 
        return false;
            
    if (Object.keys(this).length != Object.keys(x).length) return false;
                                   
    for (var p in this)
    {
        // Evitamos navegar por las propiedades "heredadas"
        if (this.hasOwnProperty(p)) {
            // No es una propiedad de x                 
            if (!x.hasOwnProperty(p)) return false;             
            switch(typeof(this[p])) {
                case 'function': 
                    // No admitimos objetos con funciones
                    return false;
                case 'object': 
                    // Comparamos los objetos
                    if (!this[p].equals(x[p]))
                         return false;  
                    break; 
                default:             
                    // Las propiedades tienes valores distintos
                    if (this[p] !== x[p])
                        return false;
                    break;
            }                        
        }
    }

    return true;                
}
Para probar este código de manera rudimentaria he hecho este código y lo he lanzado en jsFiddle y los resultado obtenidos son los esperados
var u1= {prop1 : "value1", prop2: "value2"};
var u2= {prop1 : "value1", prop2: "value2"};
console.log('u1 equals u2: ' + u1.equals(u2));

var v1= {prop1 : "value1", prop2: "value2"};
var v2= {prop1 : "value1", prop2: "value2", prop3: "value3"};
console.log('v1 equals v2: ' + v1.equals(v2));    

var w1= {prop1 : "value1", prop2: "value2"};
var w2= {prop1 : "value1", prop2: "value3"};
console.log('w1 equals w2: ' + w1.equals(w2)); 

var x1= {prop1 : "value1", prop2: "value2"};
var x2= {prop1 : "value1", prop3: "value2"};
console.log('x1 equals x2: ' + x1.equals(x2));

var y1= {prop1 : "value1", prop2: { prop3: "value3"}};
var y2= {prop1 : "value1", prop2: { prop4: "value4"}};
console.log('y1 equals y2: ' + y1.equals(y2));

var z1= {prop1 : "value1", prop2: { prop3: "value3"}};
var z2= {prop1 : "value1", prop2: { prop3: "value3"}};
console.log('z1 equals z2: ' + z1.equals(z2));
Puedes probar este código desde aquí

Se que esta no es la manera más óptima de probar el código y para esto existen framework de javascript como Jasmine o QUnit pero esta parte la dejaré para otro post.

En definitiva hemos visto que hay que estar atentos a muchos comportamientos que tiene javascript ya que algo tan simple como una comparación de objetos puede ser una vez más una tarea complicada.

Happy coding!

martes, 7 de agosto de 2012

Los operadores de comparación en javascript

Desde hace algún tiempo cada vez invierto más horas de mi jornada laboral en programar en javascript. A medida que vas programando en este lenguaje te vas dando cuenta de las muchas peculiaridades que tiene, y que te puede arruinar una jornada laboral.

Para los que vienen de programar en lenguajes como C# este tipo de sentencias son de lo más normales
if (a == b) { 
  // a y b son iguales
}
El problema está en que javascript las cosas no son como nosotros estamos acostumbrados que sean y este comparador nos pueden dar algún que otro quebradero de cabeza y más teniendo en cuenta que también tenemos un triple comparador, si como lo oyes, tenemos un triple comparador que se escribe ===.

Entonces, ¿cuál es la diferencia entre == y ===? Pues bien, el doble comparador por decirlo de una manera hace una comparación por valor y en caso que los tipos no sean igual javascript hace una coerción de tipos. El triple comparador, al contrario que el doble comparador, por decirlo de alguna manera fuerza la igualdad de tipos y del valor que estamos comparando.

Sabiendo esto, tenemos que estar atento a la hora de comparar variables porque javascript puede resolver la comparación de la manera que nosotros no esperamos.

Algunos ejemplos para que todo quede más claro
1 == 1            // true como era de esperar
1 == "1"          // true, se convierte la cadena de texto a numero
null == undefined // true
1 == true         // true
"" == false       // true
'\n' == false     // true, el '\n' se interpreta como la cadena vacía
"" == 0           // true
'\n' == 0         // true
Como vemos en todas las comparaciones (salvo la primera) esperaríamos que javascript nos devolviera false, sin embargo nos devuelve true. Para salvar esto deberíamos usar el triple comparador.
1 === 1            // sigue siendo true
1 === "1"          // false
null === undefined // false
1 === true         // false
"" === false       // false
'\n' === false     // false
"" === 0           // false
'\n' === 0         // false
De igual forma que tenemos == y ===, también tenemos != y !== cuyo comportamiento es análogo.

Otras comparaciones curiosas pero menos comunes son
NaN == NaN  // false, NaN es Not a Number y no se puede comparar
NaN === NaN // false
1.0 == 1    // true
1.0 === 1   // true, para javascript ambos son de tipo numeric
La coerción de tipos puede ser algo realmente frustrante y que nos puede volver locos un par horas, pero que nos puede venir bastante bien en algunas situaciones por lo que lo mejor es estar seguro de lo que estamos haciendo en cada momento.

Happy coding!

lunes, 6 de agosto de 2012

Introducción a Knockout (VIII) - obsersable computed y binding event

Con los binding que trae knockout de fábrica debería ser más que suficiente para la mayoría de los proyectos en los que usemos knockout. Pese a ésto knockout nos brinda la forma de poder extender estos comportamientos predefinidos para poder tener un control total sobre nuestra vista y así no tener prácticamente ninguna limitación.

Computed Observables
Dentro de los observables que nos da knockout tenemos los computed observables (prefiero no traducirlo). Son funciones, que depende de uno o más observables y que se actualizan automáticamente cuando una de sus dependencias cambia. Típicamente se usan para información que se muestra en solo lectura aunque como veremos más adelante también los computed observables pueden ser de escritura y ellos a su vez puede actualizar valores.

Supongamos esta vista
<p>Nombre: <input type="text" data-bind="value: firstname" /></p>
<p>Apellidos: <input type="text" data-bind="value: lastname" /></p>
<p>Nombre completo: <label data-bind="text: name"></p>
Y este modelo
function ViewModel(model) {  
    var self = this;  
  
    self.firstname = ko.observable('');  
    self.lastname = ko.observable('');  
    self.name = ko.computed(function() {
        if (self.firstname() == '' || self.lastname() == '') return '';
         return self.lastname() + ', ' + self.firstname();
    });
}  

var viewModel = new ViewModel();  
ko.applyBindings(viewModel);​
Como vemos establecemos dos observables sobre firstname y lastname. También definimos observable computed que actualiza la propiedad name. Esta función se lanzará cada vez que la propiedades lastname y firstname cambien. Lo realmente maravilloso es que la función detecta a que propiedades debe detectar los cambios sin que nosotros debamos hacer nada más que usarlas en el cuerpo de la función.

Podemos probar este ejemplo en el siguiente enlace.

Como comentamos antes, los computed observables también pueden ser de escritura y ellos actualizar determinados valores. He de reconocer que esto no suele ser muy común pero puede que en algún momento nos sea útil. Para hacer un computed observables de lectura y escritura en el ejemplo anterior cambiaremos la vista
<p>Nombre: <input type="text" data-bind="value: firstname" /></p>
<p>Apellidos: <input type="text" data-bind="value: lastname" /></p>
<p>Nombre completo: <input type="text" data-bind="value: name"></p>
y el modelo de la siguiente manera
function ViewModel(model) {  
    var self = this;  
  
    self.firstname = ko.observable('');  
    self.lastname = ko.observable('');  
    self.name = ko.computed({
        read: function() {
            if (self.firstname() == '' || self.lastname() == '') return '';
                return self.lastname() + ', ' + self.firstname();
        },
        write: function(value) {
            var index = value.lastIndexOf(", ");
            if (index > 0) 
            { 
                self.firstname(value.substring(index + 2));
                self.lastname(value.substring(0, index));
            }
        }
    });
}  

var viewModel = new ViewModel();  
ko.applyBindings(viewModel);​
Tal y como hicimos antes, si actualizamos el nombre y los apellidos automáticamente se actualizará el campo del nombre del completo. La salvedad en este caso, es que si actualizamos el nombre completo nosotros con el formato apellidos, nombre, se actualizarán los campos nombre y apellidos.

Podemos probar este ejemplo en el siguiente enlace.

Binding Event
Otra de las posibilidades que nos da knockout es trabajar directamente con los eventos que tienes javascript, pese a que ya tenemos algunos bindings que trabajan con ellos como puede ser el binding click.
Por ejemplo, si definimos la siguiente vista
<div>
    <input type="text" data-bind="value: message, event: { keyup: onkeyup }" />
    <label data-bind="text: status" ></label>
</div>​
y el siguiente modelo
function ViewModel(model) {  
    var self = this; 

    self.message = ko.observable('');
    self.status = ko.observable('Has escrito 0 caracteres...');
  
    self.onkeyup = function(data, event) {
        self.status('Has escrito ' + event.target.value.length + ' caracteres...');           
        return true;
    }
}  
ko.applyBindings(new ViewModel());
En este ejemplo estamos enganchándonos al evento keyup de un textbox y actualizamos un label con la información del número de caracteres que hemos introducido en el textbox.

Podemos probar este ejemplo en el siguiente enlace.

Como vemos, knoutout es bastante versátil y prácticamente podemos hacer lo que queramos. En el próximo artículo veremos como hacer nuestros propios bindings que también nos pueden ser útiles en algunos contextos.

Happy coding!

jueves, 26 de julio de 2012

Introducción a Knockout (VII) - La propiedad $index

El otro día estaba revisando la documentación de binding foreach de knockout cuando recordé que una de las novedades que había traído la versión 2.1.0 era la inclusión de la propiedad $index dentro del contexto foreach. Pensando que utilidad podría tener dentro de una aplicación real y que no fuera la de simplemente mostrar un índice ya que eso lo podemos tener usando <ol>.

Pensando un poco se me ocurrió un ejemplo donde nos podría ser útil esta nueva propiedad, así que supongamos que tenemos una colección de elementos de este tipo
public class Item
{
 public int IdItem { get; set; }
 public string Description { get; set; }
 public int Quantity { get; set; }
}
Esta colección de elementos se la tenemos que presentar al usuario y este debe escribir las cantidades que quiere para cada Item, y enviarla de nuevo al servidor. Se podría ver como un versión muy reducida de un carrito de la compra, donde tenemos los elementos que queremos comprar y podemos modificar la cantidad de elementos. Bien, para mostrar esta información y para simplificar el ejemplo he creado la siguiente modelo y acciones

Modelo
public class Model
{
 public List<Item> Items { get; set; }
}
Acciones
public ActionResult Index()
{
 Model model = new Model();
 FillModel(model);

 return View(model);
}

[HttpPost()]
public ActionResult Index(Model model)
{
 return RedirectToAction("Index");
}

private void FillModel(Model model)
{
 model.Items = new List<Item>();
 for (int i = 1; i <= 10; i++)
  model.Items.Add(new Item() { IdItem = i, Description = string.Format("Item{0}", i), Quantity = 0 });
}
Vista
<h2>Items</h2>
@using (Html.BeginForm())
{ 
 for(int i = 0; i < Model.Items.Count; i++)
 {
  <div>
   @Html.HiddenFor(m => Model.Items[i].IdItem)
   @Html.HiddenFor(m => Model.Items[i].Description)
   @Model.Items[i].Description
   @Html.TextBoxFor(m => Model.Items[i].Quantity)
  </div>
 }
 <input type="submit" value="Enviar" />
}
El aspecto de este formulario sería el siguiente

Vista

Bien, si modificamos alguna de las cantidades y le damos a enviar, obtendremos esto en la controladora

Post

Como vemos el valor introducido por el usuario (10)  ha sido "bindeado" en nuestro modelo sin problemas. Bien, ahora supongamos que queremos hacer lo mismo pero usando knockout. Para eso, debemos modificar ligeramente la vista de la siguiente manera.
@using (Html.BeginForm())
{ 
 <!-- ko foreach: items -->
 <div>
  <input type="hidden" data-bind="value: IdItem"  />
  <input type="hidden" data-bind="value: Description"  />
  <span data-bind="text: Description"></span>
  <input type="text" data-bind="value: Quantity"  />
 </div>
 <!-- /ko -->
 <input type="submit" value="Enviar" />
}

<script type="text/javascript">
 $(document).ready(function () {
  function ViewModel(model) {
   var self = this;

   self.items = ko.observableArray(model.Items);
  }
  var viewModel = new ViewModel(@Html.Raw(Json.Encode(Model)));
  ko.applyBindings(viewModel);
 });
</script>
Con esto veremos que nuestra vista es igual a la obtenida anteriormente, pero al enviar el form nos daremos cuenta que nuestro modelo no se "bindea" correctamente.


Si sabemos como funciona el bind de ASP.NET MVC veremos que este error es lógico ya que los elementos que estamos poniendo en nuestra vista no tienen el atributo name definido, pero además hay que tener en cuenta que estamos intentando "bindear" una colección por lo que tendremos que especificar el índice que ocupa el elemento en la colección. Para esto es para lo que viene de maravilla el uso de la propiedad $index dentro del contexto foreach (no es que antes no se pudiera hacer, sino que era más complicado). Con esto la vista quedaría de la siguiente manera
<!-- ko foreach: items -->
<div>
 <input type="hidden" data-bind="value: IdItem, attr: {name: 'Items['+$index()+'].IdItem'}"  />
 <input type="hidden" data-bind="value: Description, attr: {name: 'Items['+$index()+'].Description'}"  />
 <span data-bind="text: Description"></span>
 <input type="text" data-bind="value: Quantity, attr: {name: 'Items['+$index()+'].Quantity'}"  />
</div>
<!-- /ko -->
Esto generaría el siguiente código html que vemos que cumple con lo dicho anteriormente

Vista HTML

Y si hacemos el post veremos que el modelo se ha "bindeado" de nuevo correctamente



NOTA
Hay otra forma de generar la vista de una manera más "elegante" y evitando así tener que usar un bucle y teniendo a nuestra alcance el Intellisense es la siguiente. Creamos una página parcial (Partial Page) llamada Item.cshtml  (mismo nombre que la clase que contiene la colección) en el directorio View/Home/RenderPartials o Shared/RenderPartials y en ella pondremos lo siguiente
@model test.web.mvc.cs.Models.Item

<div>
 @Html.HiddenFor(m => m.IdItem)
 @Html.HiddenFor(m => m.Description)
 @Model.Description
 @Html.TextBoxFor(m => m.Quantity)
</div>
Luego en la vista tan solo deberemos poner lo siguiente
@using (Html.BeginForm())
{ 
 @Html.EditorFor(x => x.Items)
 <input type="submit" value="Enviar" />
}

Happy coding!

miércoles, 13 de junio de 2012

Introducción a Knockout (VI) - Insertando datos con ASP.NET MVC4 WebApi

En el anterior artículo de knockout vimos como podíamos llamadas AJAX para cargar nuestra UI. Hoy vamos a ver como podemos hacer el mantenimiento de nuestras entidades también de una forma sencilla. Lo primero será extender nuestro repositorio de datos para añadir cierta lógica para el almacenamiento de nuestros datos.

IRepository
public interface IBookRepository
{
  IEnumerable<Book> Get();
  IEnumerable<Book> GetList(string search);
  Book Add(Book item);
  void Remove(int id);
}
BookRepository
public class BookRepository : IBookRepository
{
    private List<Book> products = new List<Book>();
    private int _nextId = 1;

    public BookRepository()
    {
        Add(new Book
        {
            Id = 1,
            Title = "Introducing Microsoft Sql Server 2012"
        });
        Add(new Book
        {
            Id = 2,
            Title = "Introducing Windows Server 2008 R2"
        });
        Add(new Book
        {
            Id = 3,
            Title = "Visual Studio 2010"
        });
        Add(new Book
        {
            Id = 4,
            Title = "Programming Windows Phone 7"
        });
        Add(new Book
        {
            Id = 5,
            Title = "Visual Studio 2008"
        });
        Add(new Book
        {
            Id = 6,
            Title = "Microsoft .NET 4.0"
        });
        Add(new Book
        {
            Id = 7,
            Title = "ASP.NET 4.0"
        });
    }

    public IEnumerable<Book> Get()
    {
        return products;
    }

    public IEnumerable<Book> GetList(string search)
    {
        return products.Where(m => m.Title.Contains(search));
    }

    public Book Add(Book item)
    {
        item.Id = _nextId++;
        products.Add(item);
        return item;
    }

    public void Remove(int id)
    {
        products.RemoveAll(p => p.Id == id);
    }
}
BookController
public class BookController : ApiController
{
    static IBookRepository repository = new BookRepository();

    // GET /api/book
    public IEnumerable Get(string search)
    {
        return (string.IsNullOrEmpty(search) ? repository.Get() : repository.GetList(search));
    }

    // POST /api/book/
    public Book Post(Book model)
    {
        return repository.Add(new Book() { Title = model.Title });
    }

    // DELETE /api/values/5
    public void Delete(int id)
    {
        repository.Remove(id);
    }
}

Bien, con esto ya podemos irnos a la parte de cliente para ver como haríamos. La verdad es que es bastante fácil y lo único que debemos hacer es extraer los valores de las propiedades de nuestro modelo para formar un objeto JSON que pasaremos vía POST a nuestra API.

De esa manera nuestra interfaz y nuestro modelo quedarían así
<h2>Ejemplo de uso de Knockout</h2>
<h3>Insertar un libro</h3>
<div>
  Título del libro <input type="text" data-bind="value: title" /><input type="button" data-bind="click: onsave" value="Save" />
</div>

<h3>Listado de libros</h3>
<div id="search">
  <input type="text" data-bind="value: search" />
  <input type="button" data-bind="click: onsearch" value="Search" />
</div>

<!-- ko if: books().length == 0 -->
<div data-bind="if: books().length == 0">
  No hay resultados que mostrar
</div>
<!-- /ko -->

<!-- ko ifnot: books().length == 0 -->
<ul data-bind="foreach: books">
  <li ><span data-bind="text: $data.Title"></span> | <span data-bind="click: $parent.ondelete" style="cursor: pointer">[x]</span></li>
</ul>
<!-- /ko -->
Vemos que hemos añadido una pequeña sección para añadir el título de un nuevo libro, mientras que el resto de la interfaz permanece igual respecto al ejemplo del artículo anterior.
<script type="text/javascript" language="javascript">
    function ViewModel() {
     var self = this;

     self.title = ko.observable('');
            self.search = ko.observable('');
     self.books = ko.observableArray([]);

     self.onsave = function () {
      var title = self.title();
   
      if (title == '')
      {
       alert('El título es obligatorio');
       return; 
      }
   
      $.ajax({
       type: 'POST',
       dataType: "json",
       contextType: "application/json; charset=utf-8",
       url: "@Url.Action("book", "api")",
       data: { Title: title },
       success: function (pReturn) {
        self.books.push(pReturn);
       }
      });
     }

     self.onsearch = function () {
      var search = self.search();
      $.ajax({
       type: 'GET',
       dataType: "json",
       contextType: "application/json; charset=utf-8",
       url: "@Url.Action("book", "api")" + "/get/" + search,
       data: { },
       success: function (pReturn) {
        self.books(pReturn);
       }
      });
     }

     self.ondelete = function (e) {   
      $.ajax({
       type: 'DELETE',
       dataType: "json",
       contextType: "application/json; charset=utf-8",
       url: "@Url.Action("book", "api")",
       data: { id: e.Id },
       success: function (pReturn) {
        self.books.remove(e);
       }
      });
     }

     self.onsearch();
    }
    ko.applyBindings(new ViewModel()); 
</script>
Vemos que el método onsave extraemos el valor de la propiedad observable que luego usaremos para formar el JSON que pasaremos en la llamada. Para modelos más complejos podríamos serializar con el método toJSON todo el modelo de la siguiente manera:
self.onsave = function () { 
        var data = ko.toJSON(self);
   
 if (data.title == '')
 {
  alert('El título es obligatorio');
  return; 
 }
   
 $.ajax({
  type: 'POST',
  dataType: "json",
  contextType: "application/json; charset=utf-8",
  url: "@Url.Action("book", "api")",  
                data: data,
  success: function (pReturn) {
   self.books.push(pReturn);
  }
 });
}
OJO, porque este ejemplo "no funciona" porque en la serialización a JSON del modelo también se está incluyendo la propiedad books, que incluye la lista de libros que se está mostrando y esto provoca que el mapeo del modelo se haga incorrectamente en el método POST de la API. Lo he comentado para que sirva de referencia en modelos más complejos.

Otra opción es usar dos modelos diferentes en la misma vista, pero eso lo dejaremos para otro artículo que este con tanto código se ha extendido un poco.

Happy coding!

miércoles, 23 de mayo de 2012

Introducción a Knockout (V) - Cargando datos dinámicamente con ASP.NET MVC4 WebApi

Hasta ahora hemos visto varios ejemplo con knockout pero usando datos estáticos. En este artículo haremos uso de datos "dinámicos" cargados a través de Web Api (una de las funcionalidades que nos ha traído la beta de ASP.NET MVC4).

No es el objetivo de este artículo hacer explicar el funcionamiento de esta nueva funcionalidad, pero para nuestro ejemplo nos basta con lo siguiente
Controller
public class BookController : ApiController
{
  private IBookRepository repository = new BookRepository();

  // GET /api/book
  public IEnumerable<book> Get(string search)
  {
    return (string.IsNullOrEmpty(search) ? repository.Get() : repository.GetList(search));
  }
}
BookRepository
public class BookRepository : IBookRepository
{
  private List<book> books = new List<book>(); 

  public BookRepository()
  {
    Add(new Book
    {
      Id = 1,
      Title = "Introducing Microsoft Sql Server 2012"
    });
    Add(new Book
    {
      Id = 2,
      Title = "Introducing Windows Server 2008 R2"
    });
    Add(new Book
    {
      Id = 3,
      Title = "Visual Studio 2010"
    });
    Add(new Book
    {
      Id = 4,
      Title = "Programming Windows Phone 7"
    });
    Add(new Book
    {
      Id = 5,
      Title = "Visual Studio 2008"
    });
    Add(new Book
    {
      Id = 6,
      Title = "Microsoft .NET 4.0"
    });
    Add(new Book
    {
      Id = 7,
      Title = "ASP.NET 4.0"
    });
  }

  public IEnumerable<book> Get()
  {
    return products;
  }

  public IEnumerable<book> GetList(string search)
  {
    return products.Where(m => m.Title.Contains(search));
  }

  public Book Add(Book item)
  {    
    books.Add(item);
    return item;
  }
}
y finalmente IBookRepository
public interface IBookRepository
{
  IEnumerable<book> Get();
  IEnumerable<book> GetList(string search);
}
Como vemos nada complicado, una simple controladora que accede a un origen de datos un tanto especial, pero con la cual conseguimos simular el acceso a datos, y vemos como podemos consumir estos datos desde cliente.
Nuestro html está formado por los siguiente elementos, un buscador
<h2>Ejemplo de uso de Knockout</h2>
<h3>Listado de libros</h3>
<div id="search">
  <input type="text" data-bind="value: search" />
  <input type="button" data-bind="click: onsearch" value="Search" />
</div>
Un elemento que muestra un mensaje si no hay resultado
<!-- ko if: books().length == 0 -->
  No hay resultados que mostrar
<!-- /ko -->
Una lista para mostrar nuestros resultados
<!-- ko ifnot: books().length == 0 -->
<ul data-bind="foreach: books">
  <li data-bind="text: $data.Title"></li>
</ul>
<!-- /ko -->
Y nuestro modelo
<script type="text/javascript" language="javascript">
  function ViewModel() {
    var self = this;

    self.search = ko.observable('');
    self.books = ko.observableArray([]);

    self.onsearch = function () {
      var search = self.search();
      $.ajax({
        type: 'GET',
        dataType: "json",
        contextType: "application/json; charset=utf-8",
        url: "@Url.Action("book", "api")" + "/get/" + search,
        data: {},
        success: function (pReturn) {
          self.books(pReturn);
        }
      });
    }

    // Búsqueda inicial
    self.onsearch();
  }
  ko.applyBindings(new ViewModel()); 
</script>
En nuestro modelo definimos dos observadores, uno sobre el texto a buscar, y otro sobre la colección de libros que mostraremos. Es importante tener en cuenta que el observador sobre la colección de libro solo hace falta definirlo una vez y no es necesario redefinirlo cada que vez que actualicemos la colección. Es un fallo muy común y que puede darnos algún que otro quebradero de cabeza.

Inicialmente se llama al método onsearch de nuestro modelo, al igual que cada que hagamos click en el botón de buscar. Para la llamada si usaremos jQuery, y simplemente atacaremos nuestra controladora.

Otro detalle, es que para ocultar ya no es necesario poner div innecesarios, ya que he encotnrado una sintaxis más elegante que nos evita crear elementos innecesarios. En vez de poner esto
<div data-bind="if: books().length == 0">
  No hay resultados que mostrar
</div>
ponemos esto
<!-- ko if: books().length == 0 -->
  No hay resultados que mostrar
<!-- /ko -->
Vemos lo simple que queda nuestro código incluso cuando tenemos que cargar dinámicamente datos desde por ejemplo una Api.

En el próximo artículo veremos como podemos crear elementos, en nuestro caso libros, y veremos que lo podemos hacer también de una forma muy simple...

Happy coding!

martes, 22 de mayo de 2012

Introducción a Knockout (IV) - El uso de if, ifnot y visible

Hoy seguiremos con la explicación del funcionamiento básico de knockout. Está vez le tocará el turno al binding visible y veremos como controlar el flujo de la presentación mediante el uso de if o ifnot.

Bien, el propósito del binding visible es mostrar u ocultar un elemento DOM en base a un valor, y como veremos a continuación su funcionamiento es muy simple:
<h3>Listado de libros</h3>
<ul data-bind="foreach: libros, visible: mostrar">
 <li data-bind="text: $data"></li>
</ul>
<input type="checkbox" data-bind="checked: mostrar" /> Mostrar

<script type="text/javascript" language="javascript">
 function ViewModel() {
  var self = this;

  self.libros = ko.observableArray(["Introducing Microsoft Sql Server 2012",
   "Introducing Windows Server 2008 R2",
   "Visual Studio 2010", 
   "Programming Windows Phone7"]);

  self.mostrar = ko.observable(true)
 }
 ko.applyBindings(new ViewModel()); 
</script>
Podemos ver su funcionamiento aquí.

Como vemos, establecemos un checkbox que nos indicará si debemos mostrar la lista de elementos o no. Mediante el dababind checked actualizamos el valor del función observable mostrar, que a su vez, cambiará el estado del listado (ul). Si vemos el código html veremos que se añade display:none al estilo del ul cuando desmarcamos el checkbox.


El funcionamiento de if es similar al del databind visible. La principal diferencia es que mientras visible muestra u oculta en base al css, el databind if elimina los nodos que no serán visible del árbol html.

Modificando un poco nuestro ejemplo anterior ya que no podemos usar el databind forech e if en el mismo elemento veremos como funciona el databind if
<h3>Listado de libros</h3>
<div data-bind="if: mostrar">
 <ul data-bind="foreach: libros">
  <li data-bind="text: $data"></li>
 </ul>
</div>
<input type="checkbox" data-bind="checked: mostrar" /> Mostrar

<script type="text/javascript" language="javascript">
 function ViewModel() {
  var self = this;

  self.libros = ko.observableArray(["Introducing Microsoft Sql Server 2012",
   "Introducing Windows Server 2008 R2",
   "Visual Studio 2010", 
   "Programming Windows Phone7"]);

  self.mostrar = ko.observable(true)
 }
 ko.applyBindings(new ViewModel()); 
</script>
Podemos ver el ejemplo anterior funcionando aquí

Si vemos el código html del ejemplo anterior veremos esto cuando el checkbox está desmarcado


Como vemos es muy fácil modificar el aspecto de nuestra presentación usando los databind visible e if dotando a nuestra interfaz de una mayor dinamismo.

Happy coding!

lunes, 14 de mayo de 2012

Introducción a Knockout (III) - El uso del data-bind options

A raíz de una pregunta sobre como podríamos detectar la selección de un elemento en un combobox o dropdown me he puesto a mirar a fondo como funciona el data-bind options de knockout. Mirando su documentación, este data-bind, se usa en los dropdown-list o en los multiselect-list. Fuera de estos elementos el elementos este data-bind no realiza ninguna acción.

Para usarlo tan sólo debemos hacer poner esto en nuestro html
<h2>Ejemplo de uso de Knockout</h2>
<h3>Seleccione una opción</h3>
<select data-bind="options: optionValues, value: selectedOptionValue"></select>
y definir nuestro modelo MVVM de la siguiente manera
<script type="text/javascript" language="javascript">
    function ViewModel() {
     var self = this;

     self.optionValues = ['Alpha', 'Beta', 'Gamma'];
     self.selectedOptionValue = ko.observable("Gamma");
     });
    }
    ko.applyBindings(new ViewModel());
</script>
Como vemos, usamos un select html donde definiremos el data-bind options, asignándole los datos que tengamos en la propiedad optionValues de nuestro modelo y asignando el observador selectionOptionValue para detectar los cambios. En caso que queramos detectar el cambio de valores, podemos usar la función suscribe de la siguiente manera
<script type="text/javascript" language="javascript">
    function ViewModel() {
     var self = this;

     self.optionValues = ['Alpha', 'Beta', 'Gamma'];
     self.selectedOptionValue = ko.observable("Gamma");
     self.selectedOptionValue.subscribe(function (value) {
      alert("El valor seleccionado es " + value);
     });
    }
    ko.applyBindings(new ViewModel());
</script>
Podemos complicar un poco nuestro modelo para asignar un objeto en vez de una lista plana de elementos. Esto se acerca más a la realidad donde probablemente mostremos algún objeto del tipo clave / valor. También podemos hacer que el dropdown-list presente el clásico mensaje "Seleccione un valor...". Para esto definiremos nuestro select html de la siguiente manera
<h2>Ejemplo de uso de Knockout</h2>
<h3>Seleccione una opción</h3>
<select data-bind="options: optionValues, optionsText: 'value', optionsValue: 'id', value: selectedOptionValue, optionsCaption: 'Seleccione una opción...'"></select>
y nuestro modelo así
<script type="text/javascript" language="javascript">
    function ViewModel() {
     var self = this;

     self.optionValues = [{ id: "1", value: "valor1" }, { id: "2", value: "valor2"}];
     self.selectedOptionValue = ko.observable("2");
     self.selectedOptionValue.subscribe(function (value) {
      alert("El valor seleccionado es " + value.id);
     });
    }
    ko.applyBindings(new ViewModel());
</script>
Como vemos definimos un objeto simple con una propiedad id y otra propiedad valor, que asignamos a la propiedad optionValues que será usada para rellenar el dropdown-list. También definimos el optionsText, que indica la propiedad usada como texto en el select, y el optionsValue que no indica el value. El mensaje "Seleccione una opción..." es definido mediante la opción optionsCaption. Vemos que al igual que en las lista planas también podemos hacer uso de la función suscribe para manejar nosotros la selección de un elemento.

Vemos como con knockout es bastante fácil manejar los dropdown-list.

Happy coding!

domingo, 13 de mayo de 2012

jQuery desactivar el menú contextual del navegador

Para desactivar el menú contextual (típicamente el menú que sale a hacer click con el botón derecho sobre la página cargada) tan solo deberemos añadir el siguiente código a nuestra página
$(document).ready(function(){
    $(document).bind("contextmenu", function(e){
        return false;
    });
});
Si lo quisiéramos poner en todas las páginas de nuestra aplicación web tan solo debemos poner el código anterior en nuestra MasterPage (ASP.NET) o Layout Page (ASP.NET MVC).

Happy coding!

martes, 8 de mayo de 2012

Introducción a Knockout (II) - El uso de for-each y click

En mi anterior artículo hice una pequeña introducción a knockout. Hoy vamos a ver como nos puede ayudar a crear elementos en nuestra interfaz y a su vez interactuar con estos elementos de una manera muy fácil y "elegante".

Para esto tan solo debemos usar el data-bind foreach dado por knockout.Veamos su funcionamiento con el siguiente ejemplo:
<h3>Listado de libros</h3>

<ul data-bind="foreach: libros">
  <li data-bind="text: $data"></li>
</ul>

<script type="text/javascript" language="javascript">
  function ViewModel() {
    var self = this;
  
    self.libros = ko.observableArray([]);

    // Creamos nuestra colección de libros
    var t = ["Introducing Microsoft Sql Server 2012",
      "Introducing Windows Server 2008 R2",
      "Visual Studio 2010", 
      "Programming Windows Phone7"];
    self.libros(t);
  }
  ko.applyBindings(new ViewModel()); 
</script>
Vemos que creamos nuestro <ul> y ahí establecemos el data-bind foreach, sobre una propiedad de nuestro modelo. Esta propiedad está definida como un array sobre el que establecemos un observador para que cada vez que cambie se rehaga nuestro listado. Para ver este comportamiento vamos a utilizar otro data-bind, en este caso usarmos el data-bind click que nos permite interactuar sobre un click en un elemento determinado.
<h3>Listado de libros</h3>
<ul data-bind="foreach: libros">
  <li data-bind="text: $data"></li>
</ul>
<span data-bind="click: recargar" style="cursor: pointer">Recargar lista</span>

<script type="text/javascript" language="javascript">
  function ViewModel() {
    var self = this;
  
    self.libros = ko.observableArray([]);

    // Creamos nuestra colección de libros
    var t = ["Introducing Microsoft Sql Server 2012",
      "Introducing Windows Server 2008 R2",
      "Visual Studio 2010", 
      "Programming Windows Phone7"];
    self.libros(t);

    self.recargar = function () {
      t = ["Visual Studio 2008",
        "Microsoft .NET 4.0",
        "ASP.NET 4.0"];

      self.libros(t);
    }
  }
  ko.applyBindings(new ViewModel());
</script>
En este ejemplo vemos como inicialmente cargamos la lista con 4 títulos y tras hacer click sobre el recargar, ésta se recarga con los tres nuevo libros definidos en el método recargar. Vemos que el código es muy limpio sobre todo en la parte html, y con poco esfuerzo podemos cambiar la función recargar de estática a dinámica haciendo una llamada ajax para obtener datos de nuestro servicio. Puedes probar el ejemplo haciendo click aquí.

Antes la sencillez del código, la pregunta sería, ¿cómo podríamos hacer esto con jQuery? Pues sin ser un experto en jQuery sería algo así
<h3>Listado de libros</h3>
<ul id="libros"></ul>
<span id="recargar" style="cursor: pointer">Recargar lista</span>​
$(document).ready(function() {
    var t = ["Introducing Microsoft Sql Server 2012",
      "Introducing Windows Server 2008 R2",
      "Visual Studio 2010", 
      "Programming Windows Phone7"];
    bind(t);    
    
    $('#recargar').click(function() {
        t = ["Visual Studio 2008",
          "Microsoft .NET 4.0",
          "ASP.NET 4.0"];
        bind(t);
    });
    
    function bind(t)
    {
        $('#libros').empty();
        $.each(t, function(index, item) {
            $('#libros').append('<li>'+item+'</li>');
        });
    }
});​
Puedes probar el ejemplo aquí

Happy codding!

lunes, 7 de mayo de 2012

Introducción a Knockout (I)

Desde hace tiempo cada vez programo más en cliente. Para esto jQuery nos ofrece una gran ayuda, sobre todo con su gran cantidad de selectores que nos permite realizar tareas comunes como mostrar u ocultar información o crear elementos html "al vuelo" de una manera fácil.

Pues bien, una de las cosas que más odio de jQuery es tener que recorrer un div (o elemento html al gusto) para extraer toda la información que tienen los inputs para montar un JSON, y éste enviarlo al servidor. De igual forma es tedioso tener que mapear a mano cada valor recibido de "nuestro servidor" en los diferentes elementos html que tengamos en nuestra página. Tengo hecho un pequeño framework que me ayuda en este tipo de tareas (marcando los inputs, checkboxs o radiobuttons en los que deseo insertar o extraer la información) pero nunca me ha terminado de convencer.

Para resolver todo esto he descubierto, gracias a la plantilla de ASP.NET MVC4, un script que se llama Knockout. Knockout nos ayuda a interactuar de una manera fácil con la interfaz mediante el patrón MVVM (poniendo cada cosa en su sitio).

Y como todo se entiende mejor con código vamos a poner un ejemplo.
Nombre: <input data-bind="value: Nombre" type="text" />
Primer apellido <input data-bind="value: PrimerApellido" type="text" />
function ViewModel() {
    var self = this;
    
    self.Nombre = "John";
    self.PrimerApellido= "Doe";
}

// Activates knockout.js
ko.applyBindings(new ViewModel());​
Bien, ¿que hemos hecho en el ejemplo? Pues hemos vinculado (bindeado en ese idioma que tenemos los informáticos) a través del atributo data-bind la propiedad value del input (o sea, lo que se muestra) con el valor de Nombre o PrimerApellido que se definan en nuestro modelo (ViewModel).

Pero no solo estamos atados a datos estáticos sino que podemos quedarnos a la espera a que ese datos cambien para actualizar el valor en el otro lado. Veamos el siguiente ejemplo
Nombre: <input type="text" data-bind="value: Nombre" /><br />
Primer apellido <input type="text" data-bind="value: PrimerApellido" /><br />
Nombre: <span data-bind="text: Nombre"></span>
Primer apellido: <span data-bind="text: PrimerApellido"></span ><br />
function ViewModel() {
    var self = this;
    
    self.Nombre= ko.observable("John");
    self.PrimerApellido= ko.observable("Doe");
}

// Activates knockout.js
ko.applyBindings(new ViewModel());​
Vemos que si cambiamos el valor de uno de los input, éste al perder el foco actualiza el valor del span, ya que ambos se han enlazado (incluido los cambios) al valor que tenga el modelo. Para esto hemos definido un observador que nos da knockout. Como vemos con poco código hemos vinculado la actualización de un campo con nuestro modelo (y viceversa). Lo cual es ideal, para el caso de recibir valores de nuestra API a través de llamadas ajax.

A veces nos puede venir bien combinar dos valores, y establecerlos en una propiedad, pero a su vez estar atentos a su cambios. Este ejemplo lo vemos con el siguiente código
Nombre: <input type="text" data-bind="value: Nombre" /><br />
Primer apellido <input type="text" data-bind="value: PrimerApellido" /><br />
Hola <span data-bind="text: Mensaje"></span ><br />
function ViewModel() {
    var self = this;
    
    self.Nombre= ko.observable("John");
    self.PrimerApellido= ko.observable("Doe");
    self.Mensaje= ko.computed(function() {
        return this.Nombre() + " " + this.PrimerApellido();    
    }, this); 
}

// Activates knockout.js
ko.applyBindings(new ViewModel());​
Como vemos el uso de un "modelo" con estos observadores hacen que mejore la legibilidad del código que escribimos, aunque la potencia de Knockout no queda aquí, ya que también nos permite:
  • Engancharnos a eventos como el click o el checked. 
  • Establecer observadores sobre colecciones (útil para mantener una lista de los checks marcados para un filtrado).
  • Mostrar u ocultar información en base a criterios (por ejemplo una lista vacia) que podemos definir en nuestro modelo.
  • Iterar sobre colecciones para crear elementos en la UI.

domingo, 6 de mayo de 2012

jQuery maxlength en un textbox multilinea (textarea)

Si alguna vez hemos usado en asp.net los textbox multilinea nos habremos dado cuenta que la propiedad maxlength no funciona.
<asp:TextBox ID="TextBoxMultiLine" MaxLength="1" TextMode="MultiLine" runat="server"></asp:TextBox>
Que en html quedaría
<textarea name="ctl00$MainContent$TextBoxMultiLine" rows="2" cols="20" id="MainContent_TextBoxMultiLine"></textarea>
Para hacer que funcione podemos usar el siguiente código en jQuery
$(document).ready(function () {
  $('[id$=_TextBoxMultiLine]').keypress(function (e) {
    if ($(this).val().length + 1 > 1)
      e.preventDefault();
  });
});
El motivo de usar en el selector de jQuery el identificador _TextBoxMultiLine, es por la forma que tiene ASP.NET de asegurarse que un identificador sea único en la página. Si usamos ASP.NET 4.0 podemos hacer uso del modificador ClientIDMode y asignarlo con Static para evitar que el ID cambie. En se caso el script quedaría de la siguiente
<asp:TextBox ID="TextBoxMultiLine" MaxLength="1" TextMode="MultiLine" ClientIDMode="Static" runat="server"></asp:TextBox>
$(document).ready(function () {
  $('#TextBoxMultiLine').keypress(function (e) {
    if ($(this).val().length + 1 > 1)
      e.preventDefault();
  });
});
Otra posibilidad es no poner usar el atributo ClientIDMode y usar el ClientID de la siguiente manera
$(document).ready(function () {
  $('#<%= TextBoxMultiLine.ClientID %>').keypress(function (e) {
    if ($(this).val().length + 1 > 1)
      e.preventDefault();
  });
});
Si no queremos usar jQuery, podríamos llamar al un método en el evento keyUp. Para eso añadimos esto en el Page_Load de nuestra página
TextBoxMultiLine.Attributes.Add("onKeyUp", "Count(this, 1)");
function Count(text, long) {
  var maxlength = new Number(long);
  if (text.value.length > maxlength) 
    text.value = text.value.substring(0, maxlength);  
}

Happy coding!

sábado, 5 de mayo de 2012

jQuery input text numérico

Aquí les dejo un pequeño trozo de código para hacer que un input de tipo text solo admita caracteres numéricos ([0-9])
$('input').keydown(function(e) {  
  // Admite [0-9], BACKSPACE y TAB
  if ((e.keyCode < 48 || e.keyCode > 57) && (e.keyCode < 96 || e.keyCode > 105) && e.keyCode != 8 && e.keyCode != 9)
      e.preventDefault();
});
Pueden probar el código aquí ( http://jsfiddle.net/z2aEL/ )

Happy coding!

domingo, 4 de diciembre de 2011

Namespaces en javascript (2 de 2)

Siguiendo con la creación de objetos y los namespaces en javascript, ahora vamos otra forma de inicializar objetos. Está vez vamos a declarar un entorno y lo vamos a pasar como argumento de una función autoejecutable. El siguiente código nos muestra como hacerlo
var myContext = {};
(function (context) {
    var foo = 'Foo';
    var bar = 'Bar';

    // Private methods
    function getFoo () {        
        return foo;
    }

    function getBar () {
        return bar;
    }

    // Public methods
    context.getMessage = function () {
        return getFoo() + ' ' + getBar();        
    }

})(myContext);

console.log(myContext.getMessage());
console.log(myContext.getFoo()); // Uncaught TypeError: Object #<Object> has no method 'getFoo'
console.log(myContext.getBar()); // Uncaught TypeError: Object #<Object> has no method 'getBar'
Vemos como las variables 'foo' y 'bar' así como los método 'getFoo' y 'getBar' permanecen privados, por lo que solo tienen visibilidad dentro de su contexto. Lo métodos asignados al objeto pasado como parámetro (context), se podrán acceder de manera pública. Como nota, cabe destacar que este es el patrón que sigue jQuery.

This Namespace Proxy

Al leer sobre patrones y como declarar objetos en javascript unos de los patrones que más fama tiene es el patrón This Namespace Proxy (mejor no hacer traducciones) del desarrollador James Edwards. El patrón utiliza los comando apply y call. Para muchos este el patrón más elegante que hay en javascript. Veamos un ejemplo
var myContext = {};
(function () {
    var foo = 'Foo';
    var bar = 'Bar';

    // Private methods
    function getFoo() {        
        return foo;
    }

    function getBar() {
        return bar;
    }

    // Public Methods
    this.getMessage = function () {
        return getFoo() + ' ' + getBar();
    };

}).apply(myContext);

console.log(myContext.getMessage()); // Foo Bar
console.log(myContext.getFoo()); // Uncaught TypeError: Object #<Object> has no method 'getFoo'
console.log(myContext.getBar()); // Uncaught TypeError: Object #<Object> has no method 'getBar'

Siguiendo este patrón, podemos incluso asignar un mismo módulo a dos contextos direfentes, consiguiendo implementaciones paralela como podemos ver en el siguiente ejemplo
// Declarations
var myContext1 = {}, myContext2 = {};

// Method for any context
var increment = function (pSeed) {
    var lValue = pSeed || 0;
    this.increment = function () {
        return lValue++;
    }
};

increment.call(myContext1);
increment.call(myContext2, 100);

console.log(myContext1.increment()); // 0
console.log(myContext1.increment()); // 1
console.log(myContext1.increment()); // 2
console.log(myContext2.increment()); // 100
console.log(myContext2.increment()); // 101
console.log(myContext2.increment()); // 102

Conclusiones

En la programación Javascript, hay que evitar la creación de variables y métodos globales, si pretendemos integrar librerías de terceros o escribir un código que pueda ser reutilizado. Para ello tenemos que estructurarlo correctamente para evitar duplicidades que hagan que la ejecución de nuestro código no sea la esperada.

Para ello, recurrimos a la creación de objetos que actúen como contenedores de código que compartan funcionalidad. A lo largo de este artículo y del anterior hemos visto diferentes aproximaciones al mismo problem.

viernes, 25 de noviembre de 2011

Namespaces en javascript (1 de 2)

Según la wikipedia, javascript se define como un lenguaje de programación orientado a objetvos, basado en prototipos, imperativo y débilmente tipado. Se utiliza principalmente en su forma del lado del cliente (client-side), implementado como parte de un navegador web permitiendo mejoras en la interfaz de usuario y páginas web dinámicas, aunque existe una forma de JavaScript del lado del servidor (Server-side JavaScript o SSJS). Su uso en aplicaciones externas a la web, por ejemplo en documentos PDF, aplicaciones de escritorio (mayoritariamente widgets) es también significativo.



Cuando comenzamos a programar en javascript sin tener mucha idea de lo que hacemos, es frecuente declarar  variables globales sin ton ni son, que luego iremos usando según nuestra necesidades. Sin embargo, la bibliografía moderna nos recomienda reservar el uso de este tipo de variables a aquellos objetos que tienen un impacto general en el entorno de nuestra aplicación. Evitando las variables globales reducimos el riesgo de colisión entre ellas a la vez que evitamos ambigüedades.

Resumiento, hay que evitar la creacion de variables y funciones globales, salvo que sea absolutamente necesario.

Para ilustrar esto, hay que recordar que en Javascript, cualquier variable global se asigna inmediatamente a un namespace (contexto) general: el objeto window. Esto permite que podamos acceder a ella directamente por su nombre, o como una propiedad del objeto general.
var foo = 'bar'; // Definimos la variable como global  
console.log( foo ); // Usamos la variable directamente por su nombre
console.log( window.foo ); // Usamos la variable como un método

Partiendo de la premisa anterior vemos que se hace necesario buscar alguna estrategia para evitar el uso de variables globales. Para ello, lo ideal es crear pequeños objetos que encapsulen estas variables globales. La primera aproximación que se nos puede ocurrir es la siguiente

var myContext = {}  

myContext.foo = 'Foo';  
myContext.bar = 'Bar';  
myContext.getMessage = function() {  
  return myContext .foo + ' ' + myContext .bar;  
}  
 
console.log( myApp.getMessage () ); // Foo Bar

Hemos creado un único objeto global, myContext, que utilizamos como contenedor para el resto de variables y funciones. De este modo, ganamos legibilidad al poder identificar de un solo vistazo, aquellas partes de código que trabajan conjuntamente. A la hora reutilizar el código, sólo tendríamos que preocuparnos de llevarnos aquellas funciones cuyo prefijo coincida con su contexto.

Otra forma de definir nuestro objeto global es mediante la notación literal. Con esta forma podemos evitar hacer referencia a dicho objeto cada vez que necesitemos crear un nuevo método. Partiendo del ejemplo anterior, el resultado sería:

var myContext = {  
  foo : 'Foo',  
  bar : 'Bar',  
  getMessage : function() {  
    return this.foo + ' ' + this.bar;  
  }  
};

Como vemos es una forma muy sencilla y directa de declarar objetos.

Existe otro patrón llamado módulo. Este patrón se configura a partir de una función que actua como contexto dentro de nuestra aplicación. Este función se autoejecuta y devuelve el objeto que representa la interfaz pública. Este módelo se asemeja a la programación clásica orienta a objetos ya que distingimos entre métodos públicos y métodos privados ya que como sabemos javascript no implementa el concepto de clases de forma nativa, sino que creamos funciones que actuan como tales.

Para nuestro ejemplo la declaración sería de la siguiente manera
var myContext = (function() {
  var foo = 'Foo';
  var bar = 'Bar';

  var privateMethod = function() {
    return 'Private Method';
  }

  return {
    getMessage: function() {
      return foo + ' ' + bar;   
    }
  }
})();
console.debug(myContext.privateMethod()); // Uncaught TypeError: Object #<Object> has no method 'privateMethod'
console.debug(myContext.getMessage()); // Foo Bar

Este este ejemplo el método 'privateMethod' no se ha incluido en el objeto return por lo que permanece oculto y visible únicamente dentro de su contexto. Vemos que no hace falta referenciar las variables 'foo' y 'bar' con this ya que estás comparten el contexto.

Uno de los problemas que plantea este patrón es que accedemos de manera diferente a los métodos según sean públicos o privados.

var myContext = (function() {
  var foo = 'Foo';
  var bar = 'Bar';

  var getFoo = function() {
    return foo;
  }

  var getBar = function () {
    return bar;
  }

  return {
    join: function () {
      return getFoo() + " " + getBar();
    },

    getMessage: function() {
      return join();      // ERROR: Uncaught ReferenceError: join is not defined
      return this.join(); // CORRECTO
    }
  }
})();

En el ejemplo anterior la llamada al método join desde el método getMessage nos da un error. Para hacer la llamada correctamente debemos usar this. Esto no ocurre con las llamadas a los métodos 'getFoo' y 'getBar' desde el método 'join'.

Con esto acabamos la introducción a los namespace en javascript. Para la próxima dejaremos el contexto dinámico y el patrón proxy de James Edwards