Monday, March 19, 2012

Multiple active screens in pure MVC how to manage notification for particular screen ?

Inherently pure MVC does not provide support for managing multiple screens of same type in one flex application .There need a tweak in application for this .

Approach

1. Mediator Registration Names
Make name of mediator unique so that it will not be ignored as in case you register mediator with same name again for another same screen.
Sample code

In command or in view
var mediator:MyScreenMediator = new MyScreenMediator(this);
MyFacade.getInstance().registerMediator(mediator);
In MyScreenMediator.as

      public class MyScreenMediator extends Mediator
{
public static const NAME:String = "MyScreenMediator";
public function MyScreenMediator(viewComponent:MyScreen=null)
{
super(NAME + viewComponent.uid, viewComponent);
}
}
You can use this also
super(NAME + tinestamp, viewComponent); 

2. Introducing unique identifier for each screen so that mediator instance of that screen only able to listen its screen and not other screen .
You can use uid of screen for creating identifier .


Detailed implementation

1.Create a custom object for communication Object with command , proxy and mediator which will carry data and id of screen
 package salpe.model
{
public class MessageBody
{
//window ID
private var _id:String ;
// data
private var _data:Object;
public function MessageBody(id:String, data:Object)
{
_id = id;
_data = data;
}
public function get windowBranchId():String{
return _id;
}
public function get data():Object{
return _data;
}
}
}
2. Create interface which will be implemented by all screen which can be opened in multiple windows.
Better write base component and extend it .

Like >> MultiWindowVBox.mxml
 <?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
implements="salpe.model.interfaces.IMultiWindowSupportable">
<mx:Script>
<![CDATA[
private var _windowBranchId:String= "";
public function get windowBranchId():String{
return _windowBranchId;
}
public function set windowBranchId(id:String):void{
_windowBranchId = id;
}
]]>
</mx:Script>
</mx:VBox>

3. Write Base mediator which will be extended by mediators of screens which will be opened in multiple windows

 package salpe.view.mediators
{
salpe.model.MessageBody;
salpe.model.interfaces.IMultiWindowSupportable;
import mx.core.UIComponent;
import org.puremvc.as3.multicore.interfaces.IMediator;
import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.patterns.mediator.Mediator;
import org.puremvc.as3.multicore.patterns.observer.Notification;
public class MultiWindowSupportBaseMediator extends Mediator implements IMediator
{
public function MultiWindowSupportBaseMediator(NAME:String ,viewComponent:Object)
{
super(NAME, viewComponent);
}
override public function handleNotification( note:INotification ):void{
var messageBody:MessageBody = note.getBody()as MessageBody;
if(null == messageBody){
// if this is not Custom notification
handleCustomNotifications(note);
}else{
//If this is Custom notification
// Check for target screen
if(!isMyNotification(MessageBody)){
return ;
}
var body :Object = MessageBody.data;
var mynote:Notification = new Notification(note.getName(),body,note.getType());
handleCustomNotifications(mynote);
}
}
public function isMyNotification(body:MessageBody):Boolean{
if(body.windowBranchId == (viewComponent as IMultiWindowSupportable).windowBranchId){
trace(body.windowBranchId);
return true;
}
return false;
}
public function handleCustomNotifications(note:INotification ):void {
throw new Error( "Abstract method" );
}
}
}
4. Facade of pure MVC

 package salpe.facade
{
public class MyFacade extends Facade implements IFacade
{
}
}

5. Create you screen

MyScreen.mxml


 <?xml version="1.0" encoding="utf-8"?>
<custom:MultiWindowVBox
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init()"
xmlns:custom="salpe.view.components.custom.*">
<mx:Script>
<![CDATA[
[bindable]private var _count:Number = 0;
//Register Mediator -
private function init():void{
var mediator:MyScreenMediator = new MyScreenMediator(this);
MyFacade.getInstance().registerMediator(mediator);
}
public function increaseCountNotification():void{
MyFacade.sendNotification("INCREASE_COUNT",new MessageBody(windowBranchId,_count),"REQUEST");
}
public function increaseCount():void{
_count++;
}
]]>
</mx:Script>
<sas:Label text="WELCOME TO MULTIPLE WINDOW {_count}" />
<mx:Button id="myButton" label="Increase Count on This screen Only "
click="increaseCountNotification();"/>
</custom:MultiWindowVBox>


6.In Mediator MyScreenMediator.as

Handle "INCREASE_COUNT" Notification here .This notification will be ignored by all other screens as windowBrandId is different for each screen .

 package salpe.view.mediators
{
import salpe.view.components.MyScreen;
import mx.collections.ArrayCollection;
import org.puremvc.as3.multicore.interfaces.IMediator;
import org.puremvc.as3.multicore.interfaces.INotification;
import org.puremvc.as3.multicore.patterns.mediator.Mediator;
public class MyScreenMediator extends MultiWindowSupportBaseMediator
{
public static const NAME:String = "MyScreenMediator";
public function MyScreenMediator(viewComp:MyScreen=null)
{
// Register with unique Name
super(NAME + viewComp.uid, viewComp);
}
override public function listNotificationInterests():Array
{
return [
"INCREASE_COUNT"
];
}
override public function handleCustomNotifications(note:INotification):void
{
var name:String = note.getName();
var body:Object = note.getBody();
var type:String = note.getType();
switch(name){
case "INCREASE_COUNT":
(viewComponent as MyScreen).increaseCount();
break;
}
}
}