In this simple article we’ll explore how simple it is to implement History Manager functionality in a MVC Flex application and the basic rules of mvc pattern architecture.
We will use an mvc design pattern to keep the graphic views separated from the data that will store the current state of ours application.
[Gallo_Teo] - Matteo Lanzi
In this simple article we'll explore how simple it is to implement History Manager functionality in a MVC Flex application and the basic rules of mvc architecture.
I'll use Adobe Cairngorm as micro architecture but the concept is the same if you want to implement it with pureMVC.
A working example can be found here.
Application OverviewThe test application is very simple; it's a normal image gallery
that takes images from the server and displays them in "Tile View"
or in "Detail View".
The target of this tutorial is to catch a good application
strategy to implement easily the History manager, so that the user
will be able to go back and forward in his navigation through the
buttons of his browser
Therefore, the steps to create this simple application are:
1. Create a Business Class that has to request the server ( ImageDelegate.as )
2. Create a command, so that the application can query the server ( GetImageCommand.as )
3. Create a Model where the command will store the images gotten from the server ( Model.as )
4. Create the view interface to display the result
5. Implement the History Manager Strategy.
To reflect the typical cairngorm mvc architecture I've created this project structure.
That's very simple but very clean, you can reuse it for a lot of projects.
Under the business package we will find all the classes that communicate with the server, with audio stream, video stream, file stream, xml and so on. All the requests that are Asynchronies are part of the business package.
If this is the first time you've been hearing about "mvc" please
refer to Steven Webster articles on Adobe web site for more
detailed information about mvc and cairngorm.
http://www.adobe.com/devnet/flex/articles/cairngorm_pt1.html
However don't worry, these concepts are very simple and will be more clear in the next section
Oue ProducDelegate class has to request the server the list of
images, and can implement also a lot of functionality such as
resize image request, a specific image url and so on.
It has to communicate with the server side services.
In our case we really don't need to do that so we can implement it as a fake service in this way
public class ImageDelegate{
protected var responder : IResponder ;
public function ImageDelegate( responder :
IResponder) {
this.responder = responder ;
}
/**
*
* @ getImages
* get all Images from the server
* now it is a fake for the tutorial
* */
public function getImages ( ) : void {
//-- create a fake image list
var list : Array = new Array () ;
for (var i : int = 0; i< 14 ; i++ ){
var image : ImageVo = new ImageVo () ;
image.id = "id" + i ;
image.imagePreview = "./data/" +
i.toString() + ".jpg" ;
list.push( image ) ;
}
responder.result( list ) ;
}
/**
*
* example
* */
public function getImagePreview () : void {
}
// ......
/**
*
* delegate store all the functions about a remote
* service... this is the exampel : )
*
* so the commanda can reuse this in different way
* depending from the context
* */
public function resizeImage(): void { }
}
The MVC architecture is very intuitive; the concept is: " Does our application need something?" OK ! it has to give a "Command".
Think about it, does the user click a button to view a product ? Will our button dispatch something like "ViewProductCommand", or does the user want to search something ? The application will dispatch something like "getSearchedProductCommand". Our case is easier and we only need to get a list of images so we will have a command "GetImagesCommand".
In order to do that we will implements a Cairngorm class that's " ICommand" which simply has one method called execute.
public class GetImagesCommand implements ICommand, IResponder {
protected var model : Model ;
public function execute(event:CairngormEvent): void {
model = Model.instance ;
new ImageDelegate(this).getImages() ;
}
…
In the "execute" method we call "getImages" function of
ImageDelegate class (?)
I think now you can imagine the importance of the delegate:
we can have a single delegate for all the services and a lot of
different commands for a specific use.
As I said before the request to the server is asynchronous, so a
delegate has to know which command to ask for a service and give it
back to the answerer.
It's for this reason that in the command class we implement
IResponder interface too; this will allow the answerer to delegate
to the correct command.
In case we don't use delegate, our command could die after
the execute function because no object refers to it.
Here is the command
new ImageDelegate(this)
and in delegate class when it receives the answerer it does
responder.result(list) ;
this is the complete GetImagesCommandCode; you can see that , by implementing IResponder interface, we have two method ( fault and result ) that are the delegate answerer
public class GetImagesCommand implements ICommand, IResponder
{
protected var model : Model ;
public function execute(event:CairngormEvent): void
{
model = Model.instance ;
new ImageDelegate(this).getImages() ;
}
/**
*
* @result
* occurs when the delegate succefully
* query the server
* */
public function result(data:Object): void {
var list : Array = data as Array ;
if ( ! list ){
fault("no array") ;
return;
}
model.images = new ArrayCollection ( list ) ;
if ( list.length > 0 )
model.currentItem =
model.images.getItemAt( 0 ) as