¿Quieres registrarte?

Cairngorm: Problemas para actualizar la vista

Por: solisarg
27 de Diciembre del 2008
6478 de clabLevel
Otros artículos de solisarg
2,245 visitas

Intro disuasoria o disclaimer


Cairngorm es un framework creado específicamente para Flex inspirado en patrones de J2EE. Fue desarrollado por la agencia Iteration Two, luego adquirida por Adobe quien adoptó el framework como su "solución oficial", dándole soporte desde http://opensource.adobe.com y fomentando su useo entre la comunidad de Flex.

No es el único framework, y se puede nombrar a pureMVC o Fireclay como otras opciones, cada uno con sus bondades y defectos, pero todos orientados a facilitar y ordenar la tarea de construir RIAS siguiendo las mejores prácticas.

Xabi Beumala escribió hace un par de años una introducción en madeinflex donde resume las ideas básicas, aunque el mas actualizado (en inglés) artículo de los creadores del framework ilustra con el ejemplo de una tienda en línea los principales elementos en adobe.com

El problema que voy a abordar implica que conoces Cairngorm y que lo has aplicado alguna vez, sino seguramente conviene que aproveches mejor tu tiempo leyendo primero alguno de los artículos mencionados.

Problema


Al punto: cuando trabajamos con Cairngorm siguiendo la estructura propuesta, nos encontramos frecuentemente que nos falta algún tipo de feedback para poder actualizar la vista. Esto es debido básicamente a que los comandos no deben estar relacionados directamente con la vista, lo cual nos pone en aprietos a la hora de pequeñas respuestas visuales, ya que no todo se puede traducir via databindings. Pero para ilustrar mejor el problema, vamos a plantear un ejemplo



Posibles soluciones a esto:



Esta última soluciónm, explicada en [url= http://www.thomasburleson.biz/2007/06/cairngorm_view_notifications.html]www.thomasburleson.biz[/url] suena bastante bien y es la que elegí aplicar en mi último proyecto.

Solución aplicada


Se trata de una aplicación del estilo ABM (Alta-Baja-Modificación), típico CMS de teléfonos móviles para una compañía de telefonía celular. En la pantalla donde se agrega un nuevo modelo, necesito mostrar un mensaje de confirmación y volver a la pantalla inicial en donde se pueden seleccionar todas las opciones. Aquí 3 screenshots que muestran lo que necesito:

Pantalla donde se agrega el modelo




El mensaje de confirmación




la pantalla de inicio




Como es usual en cualquier estructura de Cairngorm, tengo mis piezas en su sitio:

Event


- Un evento especializado que expone el modelo agregado a través de la operación ADD_MODEL en este caso (nótese que reuse el mismo evento para las cuatro operaciones:read-insert-modify-delete)

Código :

package com.hcd.events
{
import com.adobe.cairngorm.control.CairngormEvent;
import com.hcd.vo.MarcaVO;
import com.hcd.vo.ModeloVO;

import flash.events.Event;

import mx.rpc.IResponder;

public class ModeloEvent extends CairngormEvent
{
public static var ADD_MODELO : String = "addModelo";
public static var EDIT_MODELO : String = "editModelo";
public static var DELETE_MODELO : String = "deleteModelo";
public static var GET_MODELO : String = "getModelo";

public var modelo : ModeloVO;
public var marca: MarcaVO
public var responder:IResponder

/**
* Constructor.
*/
public function ModeloEvent(type:String, res:IResponder = null)
{
super(type);
responder = res
}

/**
* Override the inherited clone() method, but don't return any state.
*/
override public function clone() : Event
{
return new ModeloEvent(type, responder);
}
}

}


En el evento he agregado un responder opcional que injecto al hacer la llamada cuando necesito. Luego este evento es mapeado al comando adecuado mediante el controlador

Controlador


Código :

package com.hcd.controller
{
import com.adobe.cairngorm.control.FrontController;
import com.hcd.events.*
import com.hcd.commands.*

public class MovilController extends FrontController
{
public function MovilController()
{
initialiseCommands();
}
public function initialiseCommands() : void
{
addCommand( MarcaEvent.ADD_MARCA, AddMarca );
addCommand( MarcaEvent.EDIT_MARCA, EditMarca );
addCommand( MarcaEvent.DELETE_MARCA, DeleteMarca );
addCommand( MarcaEvent.GET_MARCA, GetMarcas );
addCommand( ModeloEvent.ADD_MODELO, AddModelo );
...(continue)...
}

}
}

Luego el comando que recibe el responder adicional y se lo pasa al Delegator

Delegator


Código :

package com.hcd.commands
{
import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;
import com.adobe.cairngorm.control.CairngormEventDispatcher;
import com.hcd.business.MovilDelegate;
import com.hcd.events.ModeloEvent;

import mx.controls.Alert;
import mx.rpc.IResponder;
import mx.rpc.events.FaultEvent;

public class AddModelo implements ICommand, IResponder
{
private var callback:IResponder

public function AddModelo()
{
}
public function execute( event : CairngormEvent ): void
{
var evt:ModeloEvent = event as ModeloEvent
callback = evt.responder
var delegate:MovilDelegate = new MovilDelegate(this)
delegate.addModelo(evt.modelo, callback);
}
public function result( event: Object ) : void
{
Alert.show(event.result)
//refresca modelos
CairngormEventDispatcher.getInstance().dispatchEvent( new CairngormEvent( ModeloEvent.GET_MODELO) );
}

public function fault( event : Object ) : void
{
var faultEvent : FaultEvent = FaultEvent( event );
Alert.show( "¡Falla al insertar el modelo!");
}
}
}

Nótese que los comandos generan directamente el mensaje de éxito (o error) a través de un alert. Dado que el Alert puede ser lanzado estáticamente independientemente de la vista en que se esté, parece una buena opción para generar algún feedback sin necesariamente meterse con detalles de la vista.

La última pieza, el Delegate, agrega el responder a la cadena

Delegate


Código :

package com.hcd.business
{
import com.adobe.cairngorm.business.ServiceLocator;
import com.hcd.vo.MarcaVO;
import com.hcd.vo.ModeloVO;

import mx.rpc.IResponder;



/**
* @version $Revision: $
*/
public class MovilDelegate
{
private var responder : IResponder;
private var service : Object;

public function MovilDelegate( responder : IResponder )
{
this.service = ServiceLocator.getInstance().getRemoteObject( "movilServices" );
this.responder = responder;
}
... (other methods not showed) ...
public function addModelo(mod:ModeloVO, callback:IResponder):void{
var call : Object = service.addModelo(mod);
call.addResponder( responder );
call.addResponder( callback );
}
}

}


Esta llamada agrega el comando como responder, pero también el responder adicional que fue enviado desde la vista. Así el onresult del comando es invocado, pero también el callback enviado desde la vista. He aquí la implementación en el MXML

Llamada desde el MXML


Código :

 private function addModelo(evt:Event):void{
var resp:IResponder = new mx.rpc.Responder(onResults,onFault);
var event:ModeloEvent= new ModeloEvent(ModeloEvent.ADD_MODELO, resp)
model.selectedModel.marca_id = model.selectedMarca.marca_id
model.selectedModel.visible = "S"
event.modelo = model.selectedModel
CairngormEventDispatcher.getInstance().dispatchEvent(event);
}
private function onResults(res:Object):void{
this.currentState = ""
ViewStack(parent).selectedIndex = 0
}
private function onFault(evt:FaultEvent):void{
//
}


Esto es parte del código del MXML donde se agrega el modelo, El callback onResults resetea el currentState de la vista y mueve el viewstack contenedor a la pantalla principal, cumpliendo con el feedback visual sin involucrar al comando directamente. El onFault está vacío porque en este caso solo muestro el Alert de error (lo hace el comando) y no muevo la pantalla para permitir las correcciones pertinentes.

Síntesis


Se ha explicado como lograr que la vista reciba el resultado de la ejecución de un comando que accede a recursos remotos sin comprometer la estructura del framework creando relaciones directas entre los comandos y la vista, manteniendo el desacople necesario que permita la implementación rápida de callbacks visuales. Habiéndose descartado los ViewHelpers en la versión 2.1, una solución similar a esta posiblemente sea incorporada al core del framework en un futuro próximo. Estaremos atento a ello

Jorge

Enviar a twitter Enviar a facebook


También te interesa


Etiquetas flex cairngorm

Comentarios | Enviar un comentario
Muy bueno ;)
Por: Zguillez
este.... mejor usas Bindable y listo, o por último actualizas un model y te evitas tener el código engorroso. la vista debe quedar muy pero muy limpio y con código de... "view"
Por: eldervaz
La opción de usar el modelo como auxiliar para tener elementos que solo necesita la vista (el índice de un combo, entradas de texto, estados de la pantalla, etc) me parece que acumula cosas que realmente no van en el modelo, donde solo debería haber datos en común a toda la aplicación. No todo es "bindable" ... aunque esa es la base de Cairngorm. De hecho otros frameworks como Fireclay eligen limitar el tema de los bindings y usar un bus de datos para no abusar del broadcast de eventos (los bindings siempre propagan sus eventos aunque no sea necesario)

Jorge
Por: solisarg
ok, ya queda aqui como opción porque no lo mencionaste (y)
Por: eldervaz
Lo de no usar el modelo como repositorio de elementos para la vista lo pongo así:


(...)
Posibles soluciones a esto:
* Hacer que el comando hable directamente a la vista ... esto rompe la encapsulación, porque el comando no debería saber nada de la vista
* Usar algún flag en el modelo que relacionemos con la vista ... esto fuerza a guardar todo tipo de elementos en el modelo, por ejemplo el selectedIndex de un combobox o un string relacionado con el estaddo (currentState) de alguna pantalla
(....)


Lo de Fireclay ... en otro artículo ;)

Jorge
Por: solisarg
Buen articulo Jorge!

PD: Xavi, es con V :P
Por: Bleend-blog
Buen articulo, siempre es interesante saber este tipo de cosas.
Por: flashreloco
Precisamente ese es el problema que tengo ahora mismo.

Sucede que mi vista depende de 3 llamadas sequenciadas, y nesesito que se modifique el estado solo si las 3 llamadas han sido exitodas. De lo contrario tengo de dar diferente feedbacks por cada fault que se halla generado.

Me gusta mucho la solucion que propones ya que tiene mucha logica. Despues de todo, la vista siempre sabe cuando y como debe de modificarse, por eso dejemos que ella misma lo haga.
Por: yaison-blog
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.