Una sinfonía en C#

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

Tips de Javascript: Arrays

Vamos a ver algunas pocas características sobre arrays en Javascript, cortitas, pero interesantes.

Los arrays son objetos

Esto es obvio, en un punto todo es un objeto, pero en el caso de los arrays no hablamos de un objeto array como en C#, sino que un array es un objeto y cuando le agregamos elementos lo que estamos agregando son miembros del array, por ejemplo

var a = [1, 2, 3];

Esto no nos dice mucho, pero esto nos da una pista:

var a = [1, "hola", function() { console.log("hola");}];

Es por eso que no importa el tipo de cada elemento del array.

Podemos decir que un array es un objeto en el cual sus propiedades tienen por nombre el número de índice del array, es decir 0, 1, 2, 3; pero no podemos acceder a las propiedades con el punto (.) porque no está permitido que un identificado empiece con el mismo (a.1) , por eso hacemos

a[2]();

y es válido.

Las mismas reglas que se aplican a un objeto se aplican a un array

Claro, son objetos, es por eso que podemos iterar propiedades de un objeto del mismo modo que lo hacemos con un array como vemos en este post.

Hasta la próxima.

Tips de javascript: Por qué usar hasownproperty al iterar un objeto con for?

Hay una linda forma de obtener los miembros de un objeto cualquiera en Javascript de la que ya hablé, que básicamente es así:

var persona = {nombre: "leonardo", blog: "http://leomicheloni.com"};
for(var prop in persona){
	console.log(prop + " =  " + persona[prop]);
}

Y ocurre lo siguiente:

image

Perfecto, el problema es si por algún motivo agregamos funciones o propiedades a objetos de Javascript que pueden estar relacionados con nuestro objeto, es decir, imaginemos que queremos hacer una función en Object que retorne un string con cierto formato, así:

Object.prototype.format = function(){
	return "{"  + this + "}";
};

(de más está decir que es un ejemplo) lo que pasa ahora si corremos el código anterior es lo siguiente:

image

Esto puede pasar no sólo si agregamos funciones a Object sino que también si lo hacemos a String, o Array dependiendo del caso;

hasOwnProperty

Entonces la función hasOwnProperty nos permite saber si un miembro tal es del objeto en cuestión o de uno de sus prototipos, el ejemplo anterior sería así:

 

Object.prototype.format = function(){
	return "{"  + this + "}";
};

var persona = {nombre: "leonardo", blog: "http://leomicheloni.com"};
for(var prop in persona){
	if(persona.hasOwnProperty(prop)){
		console.log(prop + " =  " + persona[prop]);
	}
}

y santo remedio, ahora funciona.

image

Nos leemos!

Manejando dependencias en Javascript con RequireJs

A medida que nuestra aplicación crece en número de archivos Javascript y, más aún, si nuestra aplicación es una “single page application” (es decir todo ocurre en el mismo HTML y se va cargando y descargando contenido) y, por supuesto, usamos módulos para separar la aplicación en partes lógicas, empieza a ser complicado manejar algunos problemas como:

  1. Referencias que se cargan tarde
  2. Referencias que se cargan más de una vez
  3. Referencias que se cargan y no se utilizan

Es decir, nuestro proyecto tiene un tamaño interesante, unas cuantas referencias (bibliotecas, funcionalidad de diferentes partes de la pantalla, etc.) y nos encontramos con problemas de este tipo:

  1. Errores por referencias no cargadas
  2. Sobre-escritura de métodos por librerías que se cargan más de una vez, por ejemplo un plugin de jQuery que deja de andar cuando se carga jQuery una vez que cargó el plugin.
  3. Lentitud de la aplicación por esperar cargar cosas innecesarias o que aún no se necesitan, por ejemplo si ponemos todo en el la sección header del html para que se cargue siempre y evitar el problema 1.
  4. Crecimiento del costo de ancho de banda y peticiones al servidor para cargar referencias que no siempre se usan, imaginen que nuestra aplicación tiene una sección de carga de pedidos con un montón de validaciones pero no siempre se activa esa parte, cargar todo el código relativo a esa funcionalidad siempre no es lo más inteligente.
  5. etc.

RequireJs, una biblioteca para manejar dependencias en Javascript

Esta pequeña biblioteca nos ayuda solucionar estos problemas, vamos a enumerar alguna de sus características:

  • Carga dinámica de dependencias
  • Descarga automáticas de dependencias
  • Manejo de timeouts y carga de fallbacks

Adicionalmente podemos, gracias a una de sus utilidades logar

  • Minificación
  • Bundling

Primer ejemplo con Requirejs

Empecemos por lo más simple, creamos un HTML y agregamos la referencia a requirejs

<html>
<head>
<script type="text/javascript" src="http://requirejs.org/docs/release/2.1.9/minified/require.js"></script>
</head>
<body></body>
</html>

Primero indicamos a requirejs dónde empezar

Bien, este tag script va a ser la única referencia que vamos a tener, de todo lo demás se va a encargar requirejs, para eso tenemos que decirle cuál es el archivo por el cual va a comenzar nuestra aplicación, simplemente agregamos al mismo tag script un atributo

<script type="text/javascript" data-main="main" src="http://requirejs.org/docs/release/2.1.9/minified/require.js"></script>

con el atributo “data-main” le decimos a requirejs qué archivo es el punto de entrada de nuestra aplicación, como verán en este caso es “main.js” (el js siempre se omite), ahora dentro de nuestro archivo main.js hacemos lo siguiente:

require([], function(){
	console.log("hola require");
});

Bien, si lo ejecutamos imprime en la consola del navegador, vamos a explicar qué es esto

La función require

Esta función la vamos a usar cuando queramos cargar un módulo, el primer parámetro (que ahora es un array vacío) indica la dependencias, es decir, de qué otro módulos depende éste para correr, por ahora nada, el segundo parámetro es un callback que se ejecuta cuando todas las dependencias han sido resueltas, es decir si main.js depende de a.js y éste a su vez de b.js requirejs se va a encargar de cargar estas dependencias y asegurarse que están disponibles antes de llamar al callback (incluso si ya están cargadas no lo hace nuevamente) excelente, vamos a verlo.

main.js

require(["a"], function(){
	console.log("soy main");
});

a.js

define(["b"], function(){
	console.log("soy a");
});

En lugar de usar require() usamos define() ya que estamos definiendo un módulo, no pidiendo que se cargue, de eso se va a encargar requirejs cuando resuelva las dependencias.

b.js

define([], function(){
	console.log("soy b");
});

Ejecutamos el código y vemos el orden de resolución de dependencias

image

Utilizando dependencia

Hasta ahora comprobamos el orden de carga y no mucho más, lo interesante es tener funcionalidad que se cargan y poder utilizar los objetos que define cada módulo, bien, para eso cambiamos un poco el ejemplo:

main.js

require(["perro"], function(Perro){
	var roger = new Perro();
	roger.ladrar();
});

perro.js

define([], function(){
	var Perro = function(){
	};
	
	Perro.prototype.ladrar = function(){
		console.log("guauu!!");
	};
	
	return Perro;
});

lo corremos y…

image

Básicamente en main.js definimos la dependencia y luego la recibimos como parámetro del callback, dentro de perro.js tenemos que hacer return del objeto que queremos que el módulo reciba.

Cargando bibliotecas externas con Requirejs

Por supuesto que podemos cargar dependencias de terceros, la primera que viene a la mente es jQuery, pero como no es práctico copiarnos en código dentro de un módulo lo que hacemos es configurar requirejs para que cuando alguien le pida jQuery sepa qué hacer, del siguiente modo:

//configuramos requirejs para que cuando alguien pida jquery cargue la dependencia
requirejs.config({
	"paths": {
		"jquery": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min",
	}
});

require(["perro", "jquery"], function(Perro, $){
	var roger = new Perro();
	var saludo = roger.ladrar();
	$("body").append("<strong>" + saludo + "</strong>");
});

(modifiqué el método ladrar para que retorne un saludo)

image

básicamente llamamos al método config de requirejs y le decime qué hacer cuando le pidan jQuery.

jQuery soporta requirejs

Como muchas otras bibliotecas populares jQuery está preparada para soporta requirejs, de qué forma? bueno, si miramos el código jQuery podemos descubrirlo

	if ( typeof define === "function" && define.amd ) {
		define( "jquery", [], function () { return jQuery; } );
	}

Como vemos al final del código de jQuery esta línea se fija si existe requirejs y si es así define un módulo llamado jquery (utiliza otra sobrecarga del método define para ello)

Bien, es todo por esta vez, hay mucho más para ver, como definir dependencias entre bibliotecas de terceros y demás, pero lo dejamos para la próxima. Enjoy.

ASP.NET MVC Series–Model Binder

Como dijimos antes, una de la piezas importantes del framework es el Model Binder, quien se encarga de asociar los datos enviados en un request HTTP con parámetros en las acciones de un controlador, es decir, si un usuario llena un formulario con su email y contraseña el Model Binder es el encargado de recuperar los datos del request y hacerlos llegar al controlador en forma de parámetros, por ejemplo.

Agregando parámetros en las acciones del controlador

Vamos a tomar el ejemplo que con el que hemos estado trabajando y agregar un nuevo método con un parámetro, del siguiente modo:

    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Saludar(string nombre)
        {
            return new ContentResult { Content = "hola " + nombre };
        }

    }

La acción Saludar, recibe un parámetro, del mismo modo que lo haría si fuera un método de una aplicación Winforms, de consola, etc.

Lo interesante es que el framework se va a encargar de asociar los datos que envía el usuario con ese parámetro de manera absolutamente transparente para nosotros, o como yo diría “mágico”

Para comprobarlo vamos a correr el sitio y escribir en la barra de navegación

http://localhost:54040/home/saludar

donde por supesto localhost:5404 el la dirección donde está corriendo el sitio. Hacemos esto y vemos lo siguiente:

image

Nada impresionante, vemos que llega el texto “hola” sin más, porque no le pasamos ningún parámetro al controlador durante el request, pero vamos a hacerlo, escribimos la siguiente dirección en el navegador:

http://localhost:54040/home/saludar?nombre=leonardo

y vemos esto:

image

Como vemos al pasar el parámetro nombre en la URL, el Model Binder automáticamente asigna su valor al parámetro del controlador, de esta manera dentro del mismo no nos tenemos que preocupar por detalles de HTTP ni nada parecido.

Tipos de datos

En el primer intento no le pasamos el parámetro en el request para que el Model Binder pueda asociarlo al del controlador sin embargo eso no fue un problema, la respuesta es sencilla: el parámetro nombre es del tipo string y en C# el tipo string es un tipo por referencia, es decir, permite valores nulos, por lo tanto sino podemos un valor no pasa nada.

La pregunta es qué pasa si el parámetro fuese un tipo que no es por referencia sino por valor? por ejemplo un int, vamos a probarlo:

    public ActionResult Numeros(int valor)
    {
        return new ContentResult { Content = "ingresaste " + valor };
    }

Agregamos una nueva acción que recibe un entero y escribimos en el navegador

http://localhost:54040/home/numeros

y vemos lo siguiente

image

y vemos que se rompe justamente porque no se puede asignar null a un entero, la forma de hacerlo funcionar es pasar como parámetro cualquier valor que pueda ser convertido en int por el Model Binder, por ejemplo.

image

Funciona muy bien. Sonrisa

Se pueden pasar objetos como parámetros?

La respuesta es sí, el Model Binder es muy potente y siempre hará su mejor esfuerzo por completar los parámetros, por ejemplo

    public class HomeController : Controller
    {
        public ActionResult Login(Usuario usuario)
        {
            return new ContentResult { Content = string.Format("nombre: {0}, clave: {1}", usuario.Nombre, usuario.Clave) };
        }
    }

    public class Usuario
    {
        public string Nombre { get; set; }
        public string Clave { get; set; }
    }

Compilamos y entonces:

image

Como se ve, el Model Binder detecta que queremos una variable del tipo Usuario como parámetro, intenta crear una instancia y llenar sus propiedades con los valores que llegan en el request.

Qué hay acerca de los formularios y el método POST?

Es lo mismo, podemos hacer un formulario y enviar los datos por POST hacia el mismo método y funcionaría igual, por ejemplo

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Login(Usuario usuario)
        {
            return new ContentResult { Content = string.Format("nombre: {0}, clave: {1}", usuario.Nombre, usuario.Clave) };
        }
    }

    public class Usuario
    {
        public string Nombre { get; set; }
        public string Clave { get; set; }
    }

la vista home.cshtml

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
        <form action="/home/login" method="post">
            <p><input type="text" name="nombre" id="nombre" /><label for="nombre">Nombre</label></p>
            <p><input type="password" name="clave" id="clave" /><label for="clave">Clave</label></p>
            <input type="submit" value="Enviar" />
        </form>
    </div>
</body>
</html>

ejecutamos

image

Presionamos “Enviar” y listo

image

Mágico.

Por ahora es una buena introducción a Model Binder, la seguimos la próxima.