Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1] 2
Print
Author Topic: Register and remove mediators in runtime, where to put it?  (Read 15806 times)
hesten
Sr. Member
****
Posts: 52


View Profile Email
« on: July 06, 2009, 05:50:12 »

Hi all

I am building this app that has various windows that display various information, say a contact form and a "find store" map sort of thing (there are more ofcourse).

Since it would be foolish to intanciate all possible view components on start up, I need to create them only when the user requests them, meaning the view components and its mediator should be instanciated and removed at runtime.

Where do I put this functionality? I am thinking of using a Command that runs every time a section changes and sets the various things that need to happen (remove the previous view components, set the new one, update swfadress and so on).

But this raises another question. Where do I store the currently used Mediator and view component? In a Proxy? And what if I need the previous view component to use a transition out and wait for that to finish, before the new view component starts its transition in? Commands can't really wait for anything can they (the transistion thing is a bit tricky for me)? 

Hope this makes sense?

Regards



Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #1 on: July 06, 2009, 06:19:43 »

Ok I just noticed this thread http://forums.puremvc.org/index.php?topic=1159.0 which deal with something similar.

And Cliff suggests having the transitions in the view components, but then the mediator would need to listen for a "transition complete" before sending a notification, but wouldn't this need a 2-step approach to changing a section, e.g.

A section change is invoked and a Command tells the currently displaying mediator to transition out (the current mediator is held by reference in a proxy), when the transition is complete another notification is issued and another Command instanciates a new view component and its mediator and registers this with the facade (the approriate view component could be stored in a proxy as well?)....arg, this is confusing me :)

If a command creates view components and mediators at runtime how does it add the view component to the display list? That means that you'd need a "MainMediator" that adds view components, or some other means of the getting the main timeline from the command?

I realize I sound confused, but I'm not sure how else to explain it?
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #2 on: July 06, 2009, 04:06:29 »

Don't keep mediator or view component references in your proxies. This completely breaks the MVC pattern. The Model should know nothing about the View.

-=Cliff>
Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #3 on: July 06, 2009, 11:52:38 »

Yeah it sounds like a bad idea.

I leaning towards an approach where the currently displaying view components mediator knows it is the current.

When a "change page" notification is issued the current mediator reacts by calling the transition out method of it's view component and listens for the "transition complete" event. When this is recieved the mediator issues a notification forwarding the page name in the body, so that the appropiate mediator can react to it.

Does this sound reasonable?

Could you point me to an example app that creates mediators at runtime? I am really in doubt as how to handle that.
Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #4 on: July 07, 2009, 12:23:14 »

Ok so I did another search, and found this thread: http://forums.puremvc.org/index.php?topic=113.0 which seems to adress my situation. I'll give it a read.

Sorry if I am flooding the forum with reduntant information. (note to self: search extensively).
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: July 07, 2009, 06:49:15 »

Have a look at the Slacker demo (http://trac.puremvc.org/Demo_AS3_Flex_Slacker) for one way of doing dynamic mediator creation when instantiation of view components has been deferred.

-=Cliff>
Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #6 on: July 08, 2009, 04:17:35 »

Hi Cliff, thanks for all your help.

I've had a look at the slacker demo, and can now succesfully create the appropriate mediators and view components deferred. I am not sure if it is the preferred approach though?

I have a MainDisplayMediator whose view component is just a container for the various views that are instanciated later.

The MainDisplay view component controls transition in and transition out between the current view component and the newly added in a simple setView method.

It's the MainDisplayMediator that instanciates the appropiate view and it's mediator based on a notification.

My MainDisplayMediator method that reacts to ApplicationFacade.CHANGE_PAGE looks like this:

:
private function createNewDisplay( name:String ):void {

var display:Display;

if ( name == MainDisplay.CONTACT_VIEW ) {
display = new ContactDisplay();
mainDisplay.setView( display );
facade.registerMediator( new ContactDisplayMediator( display ) );
}
else if ( name == MainDisplay.FIND_DEALER_VIEW ) {
display = new FindDealerDisplay();
mainDisplay.setView( display );
facade.registerMediator( new FindDealerDisplayMediator( display ) );
}
...

}

All my displays inherit from Display which defines an ON_REMOVED event which its mediator listens for, and when that is invoked the Mediator removes all its listeners for the view component and removes itselv from the facade.

(the mainDisplay object calls a dispose method on the previous view component to get it to clean up its own listeners and objects)

Does that look ok?
« Last Edit: July 08, 2009, 04:19:13 by hesten » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #7 on: July 08, 2009, 08:14:08 »

This will work, but you might want to refactor/move the logic into a Command to keep the Mediator light and focused on mediation. Also, you probably want to make sure the given Mediator doesn't exist yet:

In the MainDisplayMediator:
:
private function createNewDisplay( name:String ):void {
   sendNotification( CREATE_VIEW, mainDisplay, name );
}

In the CreateViewCommand:
:
override public function execute( note:INotification ):void {
       
        var name:String = note.getType();
        var mainDisplay:MainDisplay = note.getBody as MainDisplay;

var display:Display;

if ( name == MainDisplay.CONTACT_VIEW &&
             !facade.hasMediator(ContactDisplayMediator.NAME) ) {
display = new ContactDisplay();
mainDisplay.setView( display );
facade.registerMediator( new ContactDisplayMediator( display ) );
}
        else
        if ( name == MainDisplay.FIND_DEALER_VIEW  &&
             !facade.hasMediator(FindDealerDisplayMediator.NAME)  ) {
display = new FindDealerDisplay();
mainDisplay.setView( display );
facade.registerMediator( new FindDealerDisplayMediator( display ) );
}
}

-=Cliff>
Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #8 on: July 08, 2009, 08:33:58 »

Actually I was going for an approach where the mediators and view components are completely removed. I am a bit worried about memory footprint if I keep all instances of the view components in memory, so I thought I'd try to throw them away and instanciate new ones if the page is requested again.

But I could try to keep the objects and just empty out the data in them (the view components).

And I think you're right, there seem to be piling up a bit of logic in my MainDisplayMediator at the moment. I am stilll trying to get my head around how to set up a sequence of events that span over a time frame like;

animate current page out, after that is done, animate the new one in, after that is complete, change the background.

My current approach has logic for that scattered over far to many objects for my liking.

Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #9 on: July 08, 2009, 08:46:48 »

Sure. I'd still recommend the Command approach described above and also add a complementary a RemoveViewCommand that removes the given view and its associated Mediator.

So the MainViewMediator simply hears from its child that it needs a given view to be created or removed but delegates the actual work to Commands.

-=Cliff>
Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #10 on: July 09, 2009, 05:04:10 »

I've tried tearing everything down and started over, in an attempt to use commands for most of the logic, but I must admit I am still rather confused and there are elements of my implementation that seem rather "unhandy".

My removing of the old page and building of a new page is now a macro command (invoked ApplicationFacade.CHANGE_PAGE) that looks like this:

:
override protected function initializeMacroCommand():void {
// remove previous page view and mediator
addSubCommand(RemovePageCommand);
// resolve files and stuff for the next view
addSubCommand(ResolvePageCommand);
// create new page view and mediator
addSubCommand(CreatePageCommand);
// start loading data for new page
addSubCommand(LoadPageDataCommand);
}

The RemovePageCommand looks like this:

:
override public function execute(note:INotification):void {
var currentDisplay:Display = MainDisplayMediator(facade.retrieveMediator( MainDisplayMediator.NAME )).getCurrentPage();
if ( currentDisplay != null ) {
currentDisplay.transitionOut();
}
}

As you can see this command fetches the current page from the MainDisplayMediator, I don't know where else to store the page being displayed? (the button that invokes the CHANGE_PAGE is not within the MainDisplay it is a global menu, and it knows nothing of the mainDisplay)

Then there's the ResolvePageCommand

:
override public function execute(note:INotification):void {
// get the page name
var pVo:PageChangeVO = note.getBody() as PageChangeVO;
var siteTree:SiteTreeVO = SiteTreeProxy(facade.retrieveProxy( SiteTreeProxy.NAME )).getSiteTree();
var file:String = siteTree.getFileByName(pVo.nextPage);
// modify the notification body
PageChangeVO(note.getBody()).nextPageDataFile = file;
}

This basically just does a lookup in a site tree xml to find the proper file to load for the next view. As you can see it modifies the body of the notification before the next command recieves it. Is that good practice?

On to the CreatePageCommand:

:
override public function execute(note:INotification):void {
var pVo:PageChangeVO = note.getBody() as PageChangeVO;
var pageName = pVo.nextPage;

var mainDisplayMediator:MainDisplayMediator = facade.retrieveMediator( MainDisplayMediator.NAME ) as MainDisplayMediator;
var mainDisplay:MainDisplay = mainDisplayMediator.mainDisplay;

var display:Display;

if ( pageName == MainDisplay.CONTACT_VIEW ) {
display = new ContactDisplay();
facade.registerMediator( new ContactDisplayMediator( display ) );
}
else if ( pageName == MainDisplay.FIND_DEALER_VIEW ) {
display = new FindDealerDisplay();
facade.registerMediator( new FindDealerDisplayMediator( display ) );
}
mainDisplay.setView( display );
mainDisplayMediator.setCurrentPage( display );

}

This is where it gets strange. As you can see I have methods for retrieving both the mainDisplay container and the MainDisplayMediator, and this seems wrong. But I couldn't see how else to make a command able to add an item to the display list?

Finally I load the data for the newly created page, all it does is tell a PageProxy to load the data, and when that is done the Proxy isuues a PAGE_DATA_LOADED notification which all "PageMediators" listens for. Here it get eerie again, to determine if the notification is actually relevant for the Mediator it compares the currentpage of the MainDisplayMediator to it's own view component:

:
override public function handleNotification(note:INotification):void {
switch (note.getName()) {     
case ApplicationFacade.PAGE_DATA_LOADED:
if ( MainDisplayMediator(facade.retrieveMediator( MainDisplayMediator.NAME)).getCurrentPage() == findDealerDisplay ) {
findDealerDisplay.setData( note.getBody() as XML );
findDealerDisplay.transitionIn();
}
break;

default:
break;
}
}

I know this is a lot of code, but since its run sequentially through a macrocommand it should be straight forward. The only issues are:

Can I store information on my MainDisplayMediator that the commands need to determine what to remove?
Can I expose the mainDisplay display object to a command to make it able to set a display object as a child?
Can I modify the body of a notification as it goes through a macrocommands subcommands?

Any and all remarks/critisism are more than welcome. I am prepared to take it all apart and start over if neccesary, I want to get this right :)

Regards

 
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #11 on: July 09, 2009, 07:35:48 »

This was a slightly more complex use of Commands than I was suggesting, really. I was only suggesting to farm out the creation of the new mediators to a Command.

On hearing from the view component that the page should be changed, the mediator could simply trigger the transition out. Having a listener for end of transition from the component, it could then set the next page by getting it from the Proxy and send off a note to have the new view's Mediator registered (as described in my previous post). When the Command is done, it sends a notification back to the Mediator, which responds by kicking off kick off the transition in.

The way you've got it set up with the MacroCommand, you have to have a lot of classes to pull it off, and you end up retrieving the mediator more than one time in the chain.

Also, to answer your question about modifying the Notification as it passes through the children of a MacroCommand, this is perfectly fine. Just consider the MacroCommand to be a filter chain. Each SubCommand may modify the data passing through.

-=Cliff>
Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #12 on: July 09, 2009, 09:26:52 »

Yeah the use of several classes in a macrocommand was just to break down the process into its components, they can be collected in one or two just fine.

And actually I do need to break out of the chain if the requested page is the same as the one currently being displayed.

Is there a way of returning from a MacroCommand chain "early"?

It's the whole..

transition out -> remove previous page -> look up page properties in site tree -> create new page -> load data for new page -> set data for new page -> transition in

..notification swarm I'm trying to work out, while keeping the references in place.

At the moment I've abandoned the listening for transitions before starting a new one and will be relying on timers if delays are neccesary (luckily TweenMax will handle that for me).

I'll go over it again and see if it can be reconstructed in simpler way (simple is good). Its probably me getting basic concepts wrong, but hey, I'll never learn if I don't ask :)
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #13 on: July 09, 2009, 02:36:31 »

While it is an attractive idea to take a sequential process and implement it as a series of Commands, it's not always the most efficient way to do it.

Logically, you wouldn't even send the initial request that triggers the MacroCommand if the page being requested was the same as the currently displayed page. So you wouldn't really have a need to break out of the chain. The mediator has access to the view component's current page.

No, there is no way to 'break out' of a MacroCommand. But you sometimes do need to have a 'happy path' with various steps leading to loops to gather data or whatever before continuing, or even to bail out altogether.

If you need to handle that sort of thing, you'd be far better off using the StateMachine.

Here's a link to a slide in the StateMachine Overview presentation explaining such a scenario.
http://puremvc.tv/#P003/T365

-=Cliff>
Logged
hesten
Sr. Member
****
Posts: 52


View Profile Email
« Reply #14 on: July 10, 2009, 01:23:31 »

But my MainDisplayMediator wont know about the page change at all, at the moments it's just an interface for the mainDisplay display object.

Unless the MainMediator listens for CHANGE_PAGE (which is what sets off the macro command). But that raises the question, if a Mediator listens for a notification which has a command associated, can the Mediator cancel the command? My guess is no?

The CHANGE_PAGE notification is issued from menus that have no awareness of the mainDisplay container or its mediator.

But I could have the various menu mediators retrieve the MainDisplayMediator before determining whether to send the CHANGE_PAGE notification.

I'll have a look at the state machine utility, but it feels a bit overwhelming having to incorporate that into my very limited insight into PureMVC :)
Logged
Pages: [1] 2
Print