¿Quieres registrarte?

Data Binding en Flex con la clase ChangeWatcher

Por: Otaku RzO
29 de Enero del 2009
1263 de clabLevel
Otros artículos de Otaku RzO
3,791 visitas

Al desarrollar RIAs siempre nos vemos en la necesidad de realizar alguna acción cuando un dato cambia al ser cargado desde el servidor. Flex nos ofrece el metatag [Bindable] para refrescar los cambios que sufren los datos, pero es limitado que sólo nos refresque la información en algunos casos.

Para dejar todo claro veamos un ejemplo de un Binding clásico.

Código :

package com.otakurzo.models
{
import flash.events.TimerEvent;
import flash.utils.Timer;

import mx.collections.ArrayCollection;

[Bindable]
public class UserModel
{
public var acList:ArrayCollection = new ArrayCollection();

//-- loadData(); sumilará el tiempo de respuesta de un servidor en 1.5 segundos
private var _timer:Timer;
public function loadData():void
{
_timer = new Timer(1500,1);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE,onTimerComplete,false,0,true);
_timer.start();
}
private function onTimerComplete(e:TimerEvent):void
{
// Removemos el evento, lo detenemos y destruimos el Timer
_timer.removeEventListener(TimerEvent.TIMER_COMPLETE,onTimerComplete);
_timer.stop();
_timer = null;
// --

acList.source = new Array('Otaku RzO','Eldervaz','Elecash','Zguillez','Xklibur','Fernando','eParada','Freddier');
}
//--

//-- Singleton
private static var _instance:UserModel=null;
public function UserModel(e:Enforcer){
trace('new instance of UserModel created');
}
public static function getInstance():UserModel{
if(_instance==null){
_instance=new UserModel(new Enforcer());
}
return _instance;
}
//--
}
}
class Enforcer{}

Esta clase UserModel es un Singleton que me permitirá consumir los datos desde cualquier parte de mi aplicación y tiene el Metatag [Bindable] para ver cambios que sufran sus propiedades públicas.
En acList cargaremos los datos y con la función loadData() usaremos un Timer para simular el retardo de la carga de los datos que se depositarán en acList. Como es de tipo Singleton para acceder hasta acList pondríamos:

Código :

UserModel.getInstance().acList


La interfaz:

Código :

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="199" height="324">
<mx:Script>
<![CDATA[
import com.otakurzo.models.UserModel;

private function loadUsers(e:Event):void
{
btnLoadUsers.enabled = false;
btnLoadUsers.label = "Cargando...";

//Llamamos a la función que cargará los datos
UserModel.getInstance().loadData();
}
]]>
</mx:Script>
<mx:Panel width="173" height="295" layout="absolute" styleName="opaquePanel" horizontalCenter="0" verticalCenter="0" title="Ejemplo 1">
<mx:List height="212" id="lstUsers" width="133" dataProvider="{UserModel.getInstance().acList}" x="10" y="10"></mx:List>
<mx:Button id="btnLoadUsers" label="Cargar Usuarios" click="loadUsers(event);" width="133" x="10" y="228"/>
</mx:Panel>
</mx:Application>

Importamos nuestra anterior clase, preparamos el click del botón para que cargue la data y asociamos el dataProvider del componente List con el acList de nuestra clase así:

Código :

UserModel.getInstance().acList
De esta manera los datos se actualizarán cada vez que se produzca un cambio en ellos.

Es poco código y vemos que trabaja correctamente, pero nos falto algo. El botón para cargar los datos quedo deshabilitado y debió habilitarse cuando terminaron de cargarse los datos.

Para solucionarlo podríamos usar una clase de tipo Observer o usar el Tag <mx:Binding /> o incluso una función que pondríamos así: dataProvider="{ cambio(UserModel.getInstance().acList)}" , y esa función se ejecutaría cada que cambie la data pero se pierde el binding directo hacia el dataProvider o quizás nos de algún error.

Por suerte tenemos una forma más elegante de detectar cuando se produjo un cambio y hasta cuando debemos escuchar o no esos cambios. Para lograrlo usaremos la clase ChangeWatch.

Código :

ChangeWatcher.watch(obj:Object,property:String,handler:Function):ChangeWatcher
Tiene otros parámetros opcionales pero para el uso que le daremos con estos nos basta.

Usaremos la función watch para escuchar los cambios que nos retornará una instancia de ChangeWatcher.
Parámetros:

Cuando obtengamos la instancia de ChangeWatcher podemos usar la función unwatch para dejar de escuchar cambios.

Ahora veamos el mismo código del ejemplo anterior aplicando ChangeWatcher:

Código :

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="199" height="324">
<mx:Script>
<![CDATA[
import mx.binding.utils.ChangeWatcher;
import com.otakurzo.models.UserModel;

private var cwUsers:ChangeWatcher;

private function loadUsers(e:Event):void
{
btnLoadUsers.enabled = false;
btnLoadUsers.label = "Cargando...";

//Vaciamos la data para notar los cambios
UserModel.getInstance().acList.source = new Array();

//Empezamos a escuchar cambios en la propiedad source del
//objecto acList que esta dentro de la Clase UserModel
cwUsers = ChangeWatcher.watch(UserModel.getInstance().acList,'source',onUserChange);
//--

//llamamos a la función que cargará los datos
UserModel.getInstance().loadData();
}
private function onUserChange(e:Event):void
{
//Dejamos de escuchar cambios y liberamos la variable
cwUsers.unwatch();
cwUsers = null;
//--

btnLoadUsers.enabled = true;
btnLoadUsers.label = "Cargar Usuarios";
}
]]>
</mx:Script>
<mx:Panel width="173" height="295" layout="absolute" styleName="opaquePanel" horizontalCenter="0" verticalCenter="0" title="Ejemplo 1">
<mx:List height="212" id="lstUsers" width="133" dataProvider="{UserModel.getInstance().acList}" x="10" y="10"></mx:List>
<mx:Button id="btnLoadUsers" label="Cargar Usuarios" click="loadUsers(event);" width="133" x="10" y="228"/>
</mx:Panel>
</mx:Application>

El código esta bien comentado pero resumiendo se uso ChangeWatcher antes de la carga de los datos y se dejo de escuchar al inicio de la función que fue llamada cuando cambio el dato a detectar.

El resultado:



Nota importante:


Al usar ChangeWatch coloquen bien la propiedad que quieren detectar porque se da el caso en que quieren poner directamente:

Código :

ChangeWatcher.watch(UserModel.getInstance(),'acList',onUserChange);

en vez de:

Código :

ChangeWatcher.watch(UserModel.getInstance().acList,'source',onUserChange);
Ya que acList es un objecto y source es su propiedad.

Otro sería el caso en que la clase UserModel tenga una propiedad más como: public var login_status:Boolean;
Aquí sí es correcto usar:

Código :

ChangeWatcher.watch(UserModel.getInstance(),'login_status',onUserChange);

porque login_status es una propiedad del UserModel.

Recuerden que getIntance() la estamos usando porque la clase UserModel es de tipo singleton, pero el ChangeWatcher es aplicable a cualquier tipo de objecto que tenga propiedades.

Archivos del ejemplo: descargar.

 


También te interesa


Etiquetas flex

Comentarios | Enviar un comentario
He de agregar créditos a Eldervaz que me enseño a usar mejor Flex y MVC, gracias por tu tiempo ^^ .
*Ya Elder, ya te puse! :P
Por: Otaku RzO

Otaku RzO :

He de agregar créditos a Eldervaz que me enseño a usar mejor Flex y MVC, gracias por tu tiempo ^^ .
*Ya Elder, ya te puse! :P
pero por la gran $%#$^%$&%*^&*

XD
Buen tip ^^ felicidades
Por: eldervaz
Buen Tip ;)
Muy util esa clase
Por: Zguillez
jeje yo iba a poner un post en el blog sobre esto pero me aguante hasta hacer un port del changewatcher para flash :) a ver si lo terminan con la parte en flash! :)

nice!
Por: fernando
espeso espeso ;-)
Por: eparada

fernando-blog :

jeje yo iba a poner un post en el blog sobre esto pero me aguante hasta hacer un port del changewatcher para flash :) a ver si lo terminan con la parte en flash! :)

Tú siempre fumando de esa :cc:
Uso esta clase con Cairngorm dentro de cada model y me he ahorrado muchas muchas líneas de código.
Pero usarlo como port con Flash sería fantástico!
FTW :jedi:
Por: Otaku RzO
En Flash existía una función watch, no me acuerdo si era top level o de donde salía. Hablo de hace mucho, AS1 y Flash 5, aunque puede que siguiera en AS2 (que rápido uno se olvida las cosas ...)
En fin, un buen complemento para enlazar elementos de la UI a cambios en el modelo, y sin duda tiene muchas aplicaciones más.

Buen tip ;)

Jorge
Por: solisarg
Object.watch era.

El método a usar es abrir el ChangeWatcher.as y traducirlo sin usar los imports de mx...

<metiendo presión para que alguien me ahorre el trabajo a mi >

Salu2! :D
Por: fernando
Deja un comentario
IMPORTANTE

Recuerda ser respetuoso, no insultes a otras personas, ni uses palabrotas, hay una persona al otro lado de la pantalla.

Habla bien, NO ESCRIBAS EN MAYUSCULA TODO, no escribas como en un SMS, evita cosas como "ke", "x q" y demás abreviaciones.

Aquí funcionan las etiquetas de los foros, puedes usar [b] para negrita, [img] para las imágenes, [url] para los enlaces, etc.

Si tienes preguntas técnicas, envíalas mejor al foro.