martes, 26 de mayo de 2009

JQuery - Framework de desarrollo para Javascript


Probablemente muchos de nosotros queremos entrar con entusiasmo en el mundo del desarrollo de aplicaciones ajax pero nos hemos encontrado con un gran muro debido a la complejidad e inmadurez del los IDE de desarrollo (Es muy dificil encontrar un software que permita debugear paso a paso) y la falta de un gran framework facil de usar como es el caso de otros lenguajes como ActionScript (Framework Flex), C# (.NET framework), JAVA (Java enterprice edition, etc.), PHP (Zend Framework), etc.

Bueno para todas las personas que coincidan conmigo ¡Les tengo buenas noticas! he conocido y empezado a desarrollar con un framework que me ha encantado, es super fácil de usar y con unas pocas lineas puedes crear cosas muy estilizadas, ajax y simples. Ese framework se llama JQuery ¡y los invito a todos a probarlo! Para muestra de lo que pueden lograr luego de unas pocas horas de desarrollo y aprendizaje:

Cuando se desarrolla bajo el framework de JQuery se tiene una arquitectura orientada a componentes al puro estilo de los componentes Flex o los ASP.NET Web Controls (Componentes ASP.NET). Para los que no conozcan ninguna de estas dos arquitecturas tan populares imaginen un diseño de arquitectura como un formulario web, donde cada uno de los objetos del formulario (TexInput, RadioButton, CheckButton, TextArea, Button, etc) seria un componente programable que puede ser reutilizado N veces en el futuro, podrias crear tus propios y componentes mas avanzados. Una muestra de componentes creados con JQuery y muy sencillos de utilizar son los siguientes:

Para comenzar a desarrollar y aprender sobre este grandioso Framework de Javascript debemos descargar la ultima version de JQuery e incluirla en el heather de nuestro projecto. Para descargar la ultima version pueden ingresar al siguiente directorio y seleccionar la version mas resiente o hacer click directamente en este link. De todas maneras pronto empezare a realizar tutoriales sobre el desarrollo sobre el framework de JQuery y la utilizacion detallada de algunos de los componentes que ya he probado.

Vinculos: Pagina oficial de JQuery.

Continuar leyendo...

domingo, 24 de mayo de 2009

Ejemplo Cairngorm - Agregar Contacto


Continuando la explicacion de Cairngorm realizada en la entrada anterior "Empezando con Cairngorm - Desarrollando aplicaciones Flex" en este post vamos a realizar un ejemplo de agregar un usuario (contacto) a una agenda de contactos.

Para empezar debemos descargarnos los códigos del ejemplo en el siguiente vinculo, y cargarlos a nuestro entorno de desarrollo (En mi caso Eclipse). Una vez hecho esto se encontraran la siguiente ruta de carpetas dentro del directorio source: com.adobe.cairngorm.samples.addcontact. Ubiquense en ese directorio y van a encontrar que el ejemplo esta dividido en varias carpetas: Businees, Command, Control, Model, View, VO. Estas divisiones se hace para darle un poco mas de claridad al codigo, yo agregaria una mas llamada "events" donde colocaria los eventos, pero eso es cuestion de gustos. Vamonos a la carpeta "View" y hacemos doble click sobre la vista AddContactPanel.mxml.


<?xml version="1.0" encoding="utf-8"?>
<mx:Panel
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:view="com.adobe.cairngorm.samples.addcontact.view.*"
title="MyContacts"
horizontalAlign="left" height="350">
<mx:Script>
<![CDATA[

import com.adobe.cairngorm.control.CairngormEventDispatcher;
import com.adobe.cairngorm.samples.addcontact.control.AddContactEvent;
import com.adobe.cairngorm.samples.addcontact.model.AddContact;
import com.adobe.cairngorm.samples.addcontact.vo.ContactVO;
import com.adobe.cairngorm.samples.addcontact.model.ModelLocator;
import mx.collections.ArrayCollection;


[Bindable]
public var addcontact : AddContact;

[Bindable]
public var contacts : ArrayCollection;

public function addContact() : void
{
var contactVO : ContactVO = new ContactVO();
contactVO.fullname = fullname.text;
contactVO.emailaddress = emailaddress.text;

var event : AddContactEvent = new AddContactEvent( contactVO );
CairngormEventDispatcher.getInstance().dispatchEvent( event );
}
]]>
</mx:Script>
<mx:HBox height="100%">
<mx:VBox>
<mx:Form id="addcontactForm">
<mx:HBox width="100%" horizontalAlign="left">
<mx:Text text="Add a Contact:"/>
</mx:HBox>
<mx:FormItem label="Name: ">
<mx:TextInput id="fullname"/>
</mx:FormItem>
<mx:FormItem label="Email: ">
<mx:TextInput id="emailaddress" displayAsPassword="true"/>
</mx:FormItem>
<mx:HBox width="100%" horizontalAlign="right">
<mx:Button label="AddContact" enabled="{ !addcontact.isPending }" click="addContact()"/>
</mx:HBox>
</mx:Form>
<mx:Text
text="{ addcontact.statusMessage }"
textAlign="center"/>
</mx:VBox>
<mx:VRule height="100%" strokeColor="#DDDDDD"/>
<mx:VBox paddingTop="15" paddingLeft="15" paddingRight="15" paddingBottom="15">
<mx:Text text="List of Contacts"/>
<mx:List wordWrap="true" dataProvider="{contacts}" width="200" height="220"></mx:List>
<mx:Button label="DeleteContact" textAlign="right"/>
</mx:VBox>
</mx:HBox>
</mx:Panel>



Esta vista contiene el formulario para que el usuario final introduzca los datos del contacto que quiere agregar, lo importante a destacar en este archivo son las siguientes lineas:
public function addContact() : void
{
var contactVO : ContactVO = new ContactVO();
contactVO.fullname = fullname.text;
contactVO.emailaddress = emailaddress.text;

var event : AddContactEvent = new AddContactEvent( contactVO );
CairngormEventDispatcher.getInstance().dispatchEvent( event );
}

La funcion addContact se encarga de crear un objeto ContactVO llenandolo con la información introducida en el fomulario por el usuario. Luego crea y despacha un evento Cairngorm llamado AddContactEvent. Vamos a ubicarnos con el mismo esquema de la entrada "Empezando con Cairngorm - Desarrollando aplicaciones Flex":

En este momento nos encontramos en el paso numero 1 del flujo. Todos los eventos despachados en Cairngorm deben heredar de la clase CairngormEvent, y, al momento de crearlos, debemos especificar en el controlador con que comando va asociado este evento, veamos el codigo de la clase AddContactEvent.cs:

package com.adobe.cairngorm.samples.addcontact.control
{
import com.adobe.cairngorm.control.CairngormEvent;
import com.adobe.cairngorm.samples.addcontact.vo.ContactVO;

/**
* El evento se dispara cuando el usuario presiona "agregar contacto"
*/
public class AddContactEvent extends CairngormEvent
{
/**
* El contacto que se desea agregar
*/
public var contactVO : ContactVO;

/**
* El contructor, te obliga a especificar el contacto
*/
public function AddContactEvent( contactVO : ContactVO )
{
super( AddContactControl.EVENT_ADD_CONTACT );
this.contactVO = contactVO;
}
}
}

Como pueden ver es un codigo bastante sencillo. Lo unico que debemos tomar en cuenta es heredar de la clase CairngormEvent y de especificar cualquier información que deseamos que este disponible en el comando o delegado o servicio (en este caso nos interesa tener el contacto que se va a agregar).

Para hacer el vinculo entre el comando y el evento ahora debemos ir a la clase AddContactControl para realizar las especificaciones de la siguiente manera:

package com.adobe.cairngorm.samples.addcontact.control
{
import com.adobe.cairngorm.control.FrontController;
import com.adobe.cairngorm.samples.addcontact.commands.AddContactCommand;

public class AddContactControl extends FrontController
{
public function AddContactControl()
{
addCommand( AddContactControl.EVENT_ADD_CONTACT, AddContactCommand );
}

public static const EVENT_ADD_CONTACT : String = "addcontact";
}
}

En la linea addCommand( AddContactControl.EVENT_ADD_CONTACT, AddContactCommand ); realizamos el verdadero vinculo entre nuestro evento y el comando. Ahora debemos proceder a crear un comando para manejar las peticiones al servidor. En este momento nos encontramos en el paso dos del flujo Cairngorm, recuerden que es obligatorio hacer al menos una instancia del controlador en la aplicacion, ademas, este controlador debe heredar de la clase FrontController.

Ahora debemos pasar al siguiente paso (crear un comando). Los comandos implementan las interfaces Command y Responder. Por ello deben tener tres metodos principales: execute, onResult y onFault. El primero de ellos es ejecutado automaticamente por el controlador cuando se dispara alguna evento que este enlazado con este comando, el segundo se ejecuta automaticamente una vez que el delegado ha concluido la ejecucion del servicio satisfactoriamente, el ultimo de estos metodos es igual al segundo, con la salvedad que se ejecuta cuando ocurrio algun error no controlado durante la ejecucion del servicio. Ese comando debe tener una instancia del modelo para poder insertar la informacion obtenida del servicio durante el paso 9 del diagrama de flujo.
A continuacion el codigo del comando:

package com.adobe.cairngorm.samples.addcontact.commands
{
import mx.rpc.events.ResultEvent;
import com.adobe.cairngorm.business.Responder;
import com.adobe.cairngorm.commands.Command;
import com.adobe.cairngorm.control.CairngormEvent;
import com.adobe.cairngorm.samples.addcontact.business.AddContactDelegate;
import com.adobe.cairngorm.samples.addcontact.control.AddContactEvent;
import com.adobe.cairngorm.samples.addcontact.model.ModelLocator;
import com.adobe.cairngorm.samples.addcontact.vo.ContactVO;

public class AddContactCommand implements Command, Responder
{
private var model : ModelLocator = ModelLocator.getInstance();

public function execute( event : CairngormEvent ) : void
{
model.addcontact.isPending = true;
var delegate : AddContactDelegate = new AddContactDelegate( this );
var addcontactEvent : AddContactEvent = AddContactEvent( event );
delegate.addcontact( addcontactEvent.contactVO );
}

public function onResult( event : * = null ) : void
{
model.addcontact.contactVO = ContactVO( event );
model.addcontact.isPending = false;

//Simplify - Used an array of strings instead of ContactVO's
model.contacts.addItem(ContactVO(event).fullname+" "+ContactVO(event).emailaddress);

}

public function onFault( event : * = null ) : void
{
model.addcontact.statusMessage = "Could not send contact information to the server.";
model.addcontact.isPending = false;
}
}
}

Para el siguiente paso debemos crear nuestra clase delegate (Delegado). Los delegados son los encargados de ejecutar los servicios que se encuentren definidos en el Localizador de servicio (ServiceLocator).

Para crear nuestro delegado debemos crear una clase que tenga los siguientes atributos globales:
private var responder : Responder;
private var service : Object;
El primero de ellos es una instacia del Comando que acabamos de agregar en el paso anterior, nos permitirar llamar a los metodos onResult y onFault dependiendo de la ejecucion del servicio. Debemos crear un metodo para cada servicio asociado con este delegado, en el ejemplo actual no tenemos ningún servicio asociado en el Localizador de Servicios, por lo que vamos a finjir la ejecucion de uno, utilizando un timer de 2 segundos (2000 Milisegundos). A continuacion el codigo de la clase AddContactDelegate.cs:

package com.adobe.cairngorm.samples.addcontact.business
{
import com.adobe.cairngorm.business.Responder;
import com.adobe.cairngorm.business.ServiceLocator;
import com.adobe.cairngorm.samples.addcontact.vo.ContactVO;

import flash.utils.setTimeout;

import mx.rpc.AsyncToken;
import mx.rpc.events.ResultEvent;

public class AddContactDelegate
{
private var responder : Responder;
private var service : Object;

public function AddContactDelegate( responder : Responder )
{
//this.service = ServiceLocator.getInstance().getService( "addcontactService" );
this.responder = responder;
}

public function addcontact( contactVO : ContactVO ): void
{
//var token : AsyncToken = service.addcontact( contactVO );
//token.resultHandler = responder.onResult;
//token.faultHandler = responder.onFault;

//for demo purpose: simulate remote service result
setTimeout( addcontactResult, 1000, contactVO );
}

private function addcontactResult( contactVO : ContactVO ): void
{
if( 1 )
{
responder.onResult( contactVO );
}
else
{
responder.onFault();
}
}
}
}

Por ultimo nos queda el archivo Services.mxml que hereda de la clase ServiceLocator, este, es el Localizador de servicios de la aplicacion, debemos tener todos nuestros objetos remotos, metodos remotos, etc. Definidos en este archivo. En el este ejemplo se encuentra comentada una declaracion de un objeto remoto como ejemplo.

<?xml version="1.0" encoding="utf-8"?>
<cairngorm:ServiceLocator
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:cairngorm="com.adobe.cairngorm.business.*">
<!--commented for demo-->
<!--
<mx:RemoteObject
id="addcontactService"
destination="addcontactService"
showBusyCursor="true"
result="event.token.resultHandler( event );"
fault="event.token.faultHandler( event );">
</mx:RemoteObject>
-->
</cairngorm:ServiceLocator>

Tambien debemos hacer una instancia de este ServiceLocator en el inicio de ejecucion del proyecto. En resumen debemos hacer instancias de los siguientes componentes antes de iniciar la ejecucion de las funcionalidades del proyecto:
  • Controlador: AddContactControl en este ejemplo.
  • ServiceLocator: Services en este ejemplo.
  • ModelLocator: Se llama ModelLocator tambien en este proyecto.
Para que visualizen mejor como hacer las instancias que acabo de mencionar vamos a observar el codigo de la clase Applicacion del ejemplo:

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:view="com.adobe.cairngorm.samples.addcontact.view.*"
title="MyContacts"
horizontalAlign="left" height="350">
<mx:Script>
<![CDATA[

import com.adobe.cairngorm.control.CairngormEventDispatcher;
import com.adobe.cairngorm.samples.addcontact.control.AddContactEvent;
import com.adobe.cairngorm.samples.addcontact.model.AddContact;
import com.adobe.cairngorm.samples.addcontact.vo.ContactVO;
import com.adobe.cairngorm.samples.addcontact.model.ModelLocator;
import mx.collections.ArrayCollection;


[Bindable]
public var addcontact : AddContact;

[Bindable]
public var contacts : ArrayCollection;

public function addContact() : void
{
var contactVO : ContactVO = new ContactVO();
contactVO.fullname = fullname.text;
contactVO.emailaddress = emailaddress.text;

var event : AddContactEvent = new AddContactEvent( contactVO );
CairngormEventDispatcher.getInstance().dispatchEvent( event );
}
]]>
</mx:Script>
<mx:HBox height="100%">
<mx:VBox>
<mx:Form id="addcontactForm">
<mx:HBox width="100%" horizontalAlign="left">
<mx:Text text="Add a Contact:"/>
</mx:HBox>
<mx:FormItem label="Name: ">
<mx:TextInput id="fullname"/>
</mx:FormItem>
<mx:FormItem label="Email: ">
<mx:TextInput id="emailaddress" displayAsPassword="true"/>
</mx:FormItem>
<mx:HBox width="100%" horizontalAlign="right">
<mx:Button label="AddContact" enabled="{ !addcontact.isPending }" click="addContact()"/>
</mx:HBox>
</mx:Form>
<mx:Text
text="{ addcontact.statusMessage }"
textAlign="center"/>
</mx:VBox>
<mx:VRule height="100%" strokeColor="#DDDDDD"/>
<mx:VBox paddingTop="15" paddingLeft="15" paddingRight="15" paddingBottom="15">
<mx:Text text="List of Contacts"/>
<mx:List wordWrap="true" dataProvider="{contacts}" width="200" height="220"></mx:List>
<mx:Button label="DeleteContact" textAlign="right"/>
</mx:VBox>
</mx:HBox>
</mx:Panel>



Fijense que aparte de hacer todas las instancias necesarias, tambien le decimos al datagrid que debe enlazar (Binding) su dataprovider con el objeto "contacts" del ModelLocator (model), esto lo hacemos para que cada vez que actualizamos este modelo de datos, se actualice esta vista (el datagrid se llena con exactamente la misma data que tenga model.contacts).

Una vez llamado el servicio y ejecutado correctamente la respuesta de este, nos llegara automaticamente al comando que definimos (AddContactCommand.cs). La respuesta se vera reflejada en el metodo "onResult" donde debemos utilizar la instancia del modelo que tenemos para agregar los datos obtenidos en el modelo de datos, de esta manera la vista se actualizara automaticamente gracias al binding automatico. Los pasos 6,7,8 y 9 del flujo se ejecutan muy rápidamente como pueden darse cuenta, todo gracias a las configuraciones y métodos de programacion utilizados en la arquitectura. A continuacion les dejo el ejemplo funcionando y un vinculo para descargar el codigo fuente. Cualquier pregunta no duden de escribirla en los comentarios de este post.



Continuar leyendo...