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]
Print
Author Topic: Popup System: Commands or Mediators to handle popup interaction?  (Read 12313 times)
sideDoor
Full Member
***
Posts: 25


View Profile Email
« on: July 19, 2010, 01:04:26 »

Hello,

Managing popups, the saga:  I've sifted through the few posts on managing popups in an application and in a pureMVC application.  I am currently refactoring a popup system for reuse-ability, and I want to open the discussion for feedback.  We're using AS3 (no Flex Framework) with pureMVC multicore...

THE BACKGROUND: THE PROBLEM
I started with a PopupMediator as an API to create/show popups within the application.  The PopupMediator's View was actually not the popupView itself, but a top-level view container into which popupViews would be shuttled onto and off of the stage, so that they were always at a z-level above other views in the application.

At first there was only a few popups, a common popupView and a few specialized popups, each extending an AbstractPopupView.  Because transitioning popups visually onto and off of the stage was the same for all popups, the AbstractPopupView defind methods for this feature, as well as an activate/deactivate API for sub-components that could be overridden by specialized, concrete popups.  This worked very well until the application grew, and need for more specialized popups arose, and you can well imagine that the PopupMediator bloated well beyond its original intention, with an API to show each needed popup as well as handlers for each popupView's interaction.  Maintenance is a drag!

THE FOREGROUND: THE SOLUTION
So, to refactoring a system:

I'm thinking that I am going to encapsulate ALL requests for a concrete popupView into a single command PER concrete popupView.  I can generally break the requests to be handled for a popup into 3 types:

1. CREATE_POPUP: The creation of the popupView and populating it with the appropriate data, and any actor can send a notification to fire this
2. HANDLE_POPUP: The handling of user interaction with the poupView, generally, this will be responses to MouseEvents.
3. DESTROY_POPUP: The deactivation, removal and destruction of the popupView.

So for each concrete popupView, I will have a HandleMyConcretePopupCommand extending a AbstractHandlePopupCommand.  And using the Template Method to call the appropriate method, based on the TYPE param of the pureMVC notification, I will handle the request appropriately WITHIN THE SAME COMMAND.

So for Creation, because we're dealing with concrete Commands, we don't really need to accept a 'createPopupVO', with pairing popupView Class and Mediator; the popupView can be instantiated directly herein.  However, if the popupView requires specific view-data, we can pass it in the note body and pass along to the Command's create method, where it will be typed and thus expected.  The popupView will be passed to the PopupMediator, the PopupMediator will listen for MouseEvents.

As MouseEvents generated by the poupView are handled by the PopupMediator, the PopupMediator will in turn send a notification paired to the same HandleMyConcretePopupCommand, but in this case, I will accept the MouseEvent in the notification, and call the handlePopup method in the Command, which will give us the popupView as the target or currentTarget.

For Destruction, I will kill anything that needs killing, and remove the popupView from the displayList, and destroy the popupView.

Given that Command objects in pureMVC are created and destroyed on usage, the handling of all three types of popup requests, creation, mouse handling, and destruction, can be neatly collected in one Command object.  I just need to be sure that Commands are in fact destroyed after usage, and not kept floating around - this might throw a wrench into the cogs.  Can someone advise specifically here?

I know that I could (and by suggested best practice, SHOULD), create a Mediator per popupView that merits complex interaction.  But given that the Mediator in pureMVC is only suppose to act on behalf of the View Component when communicating with the other actors of the pureMVC system (data and controllers), I want to suggest I keep only ONE PopupMediator for the application.  This Mediator can simply listen for MouseEvents generated by the popupView, and send a note mapped to the appropriate Command.  I'll figure out a way of mapping the target of MouseEvent to the appropriate HandleMyConcretePopupCommand.  But any specific logic that needs to be handled because of user interaction can be dealt with in the HandleMyConcretePopupCommand handlePopup method, and not directly in the View or the PopupMediator.  The only time this becomes 'iffy' is in the case where handling the popup might require adding and handling a contextual listener to the popup; still, this could be handled in the same manner, by routing it through the one PopupMediator, which will fire the appropriate HandleMyConcretePopupCommand, which will handle the context.  It's just when I think about it: one concrete Mediator to one concrete popupView? Too much work...

To me, this seems clean: all Controller like code per popupView is collected into one Command per popupView.  This will make management much easier, I think.

Adding, removing, and z-level of the popView could either be handled by the one PopupMediator, or, by a PopupManager Singleton not related to pureMVC.

Anyway, that's what I'm thinking...someone stop me if I'm crazy!  I'm happy to share the implementation, and will do so as I develop it, but I would be grateful for comments as I'm planning the building of this spaceship...

OR, ahh, what about the Factory Method in this system...perhaps the creation of concrete popups should be handled by parallel creation Objects, hmm...so many routes here...

Thanks, sd
Logged
jpwrunyan
Sr. Member
****
Posts: 84


View Profile WWW Email
« Reply #1 on: July 21, 2010, 11:57:06 »

Wow.  This seems a lot more complicated than necessary.  It may just be that I still don't grasp everything that's going on in the application that requires the complexity.

I will just suggest that it might be helpful to not think of popups as anything more special than your other view components.  Whether the view is attached to a ViewStack, is a static part of the application, etc. you will need some formal way of inserting a given view component into the (Flex/Flash) application's view hierarchy.

Most applications will dynamically change their view according to an event/notification.  Like navigating to a different screen via a main menu.  To do this, I send a notification with the view component as the body.  The notification is handled by the Mediator associated with the main view component.  That Mediator then calls logic on its own viewComponent, such as addChild() or calls PopupManager.addPopUp, whatever.  This process is completely independent from any other initialization/instantiation logic (registering proxies, mediators, etc).  It is simply a branch in the framework for displaying components that are essentially children of the main view.

I struggled with how to handle popups for a long time until I eventually came around to thinking of them as no different from any other dynamically displayed view component in the application.

Here's a concrete example of what I might do:
:
public class DisplayEmployeePopUpCommand extends SimpleCommand {
  override public function execute(notification:INotification):void {
    //get the mediator of the component I want to display, or instantiate it
    if (!facade.hasMediator(DisplayEmployeePopUpMediator.NAME)) {
      //I create the actual viewComponent inside DisplayEmployeePopUpMediator
      facade.registerMediator(new DisplayEmployeePopUpMediator());
    }
    var viewComponent:Object = facade.retriveMediator(DisplayEmployeePopUpMediator.NAME).viewComponent;
    sendNotification(ApplicationConstants.SHOW_POPUP, viewComponent);
    //any other necessary business logic can be handled by this command.
  }
}

ApplicationConstants.SHOW_POPUP is handled by the main view's mediator class.  It could also be handled by another command.  You could change the format of body if you like (I just give it the viewcomponent and that's good enough for my purposes).  You could add type to the notification if your popups have different display classifications (or if you wanted to expand and use this technique not just for popups, but for screen navigation, etc).  From here I think you can infer how I go about hiding popups, destroying them, etc.

As you can see, since the "popUp" is just a viewComponent with its own Mediator, I don't hammer my head against the desk trying to come up with some architecture for it and all other popups that encapsulates every scenario that might arise in my application.

It's just a view component with a Mediator which can handle anything that might arise on a client meeting by client meeting basis.  Inelegant, perhaps.  But simple and straightforward in my opinion.

Anyway, I hope this is at least food for thought.
Logged
sideDoor
Full Member
***
Posts: 25


View Profile Email
« Reply #2 on: July 23, 2010, 12:31:04 »

@jpwrunyan

Man, many thanks for the reply...in fact, the part where you mentioned banging your head against the desk was most helpful and brought into focus the issue: I'm trying to refactor-in the consideration of too many exceptions!  The beast we're using to manage our popups in our application out-grew its pen...and part of the problem is that we're just using the PureMVC framework incorrectly on this project in particular....so, there's a lot of tight coupling going on, but my hands are tied on that one...and so our mediators are becoming massive controllers...and a headache to manage.

My deal overall is that I'm not too keen on creating a Mediator per PopupVew, and would prefer to have a Manager handle the bulk of queuing popupViews to be rendered and removed, and specific controllers for popups, if needed, to handle their specialized mouse-events.

A black-box type seal I guess is what I'm after for a PopupManager, so it can be used anywhere.  So I'll develop my PopupManager with this in mind.  I'll post my work for any interested parties as I go.

Regardless, I totally understand your approach to shuttling views into the application via PureMVC, and use a similar system myself (sending a notification that a view was created along with the view-component, allow mediators to listen for this note, if the view should be managed by the mediator, it will be added therein, etc, something like that...).

Thanks again, more soon,
sd
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #3 on: July 25, 2010, 01:40:55 »

If you haven't yet, you might want to read Simon Bailey's PopManager posts: http://www.newtriks.com/?p=329

-=Cliff>
Logged
jpwrunyan
Sr. Member
****
Posts: 84


View Profile WWW Email
« Reply #4 on: July 25, 2010, 08:46:38 »

@sidedoor

I have the exact same situation here too.  The people who started working with the PureMVC framework didn't exactly understand it (nor did I originally), and they extended a lot of framework classes making them too-clever-by-half.  Then, like your project, the requirements outstripped the framework, and there's spaghetti all over the place.  You have my sympathy!

@cliff

thanks for the link.  I remember scouring the forums a long time back looking for how to handle popups best, but I guess I never found a reference to this page.  always appreciate your help!

edit: one point where I would differ with his approach is that he chooses to set his data using one single command and then accommodate different mediator classes in a switch statement (the setPopData() method).  In my case, this would lead to a monolithic switch statement.  Ergo, I will still probably keep the business logic for each popup in its own specific command/notification, and delegate the placement of popups on screen to the separate common shared notification.  Still, with a little tweaking, I think he could make his popup mediators have an interface for his setPopData() method and just pass some arbitrary data to it and leave the Mediator to take care of the rest.  Also, no problem putting some business logic in the Mediator's onRegister() in this case is there???  (I'm thinking specifically getting data from proxies and sending other notifications that might affect the rest of the application--this is what my class-specific commands currently do).

edit2: just so you can see concretely what I am doing, here are the two (very simple) commands for handling popups that I use currently:
:
public class AddPopUpCommand extends SimpleCommand {
public function AddPopUpCommand() {
super();
}

override public function execute(notification:INotification):void {
var popUp:UIComponent = UIComponent(notification.getBody());
var mainViewMediator:IMediator = facade.retrieveMediator(MainViewMediator.NAME);
var mainView:UIComponent = UIComponent(mainViewMediator.getViewComponent());

if (popUp.parent == mainView.systemManager) {
PopUpManager.bringToFront(popUp);
} else {
PopUpManager.addPopUp(popUp, mainView);
}
PopUpManager.centerPopUp(popUp);
}
}
:
public class RemovePopUpCommand extends SimpleCommand {
public function RemovePopUpCommand() {
super();
}

override public function execute(notification:INotification):void {
var popUp:UIComponent = UIComponent(notification.getBody());
var mainViewMediator:IMediator = facade.retrieveMediator(MainViewMediator.NAME);
var mainView:UIComponent = UIComponent(mainViewMediator.getViewComponent());

if (popUp.parent == mainView.systemManager) {
PopUpManager.removePopUp(popUp);
}
}
}

example of specific popup

:
public class ShowMyPopUpCommand extends SimpleCommand {
public function ShowMyPopUpCommand() {
super();
}

override public function execute(notification:INotification):void {
//frequently changing business logic goes here...
//most people can get by without defering Proxy and Mediator instantiation like this...

if (!facade.hasProxy(MyPopUpDataProxy.NAME)) {
facade.registerProxy(new MyPopUpDataProxy());
}

if (!facade.hasMediator(MyPopUpMediator.NAME)) {
facade.registerMediator(new MyPopUpMediator());
}

var myPopUpMediator:IMediator = facade.retrieveMediator(MyPopUpMediator.NAME);

sendNotification(ApplicationConstants.SHOW_POP_UP, myPopUpMediator.getViewComponent()); //this can also be in the Mediator's onRegister() method
}
}

Note that this is for standard PureMVC, not MultiCore.  You can get even more power out of these if you change the notification body from a reference to the popup into a VO that contains the popup and any other information geared towards common functionality (like if you want to check/instantiate your Mediators here as well, or specify different parents for the popup, etc.).  Also, in a perfect world, ShowMyPopUpCommand, ShowMyOtherPopUpCommand, and ShowMyYetAnotherPopUpCommand would all use the same logic structure and therefore become unnecessary--the necessary logic would all be in MyIdealAddPopUpCommand.  For me this just isn't doable right now (without that aforementioned monolithic switch statement).

For now I keep it simple so I can avoid painting myself into a corner.  This comes at the cost of having a lot of Command and Mediator classes in our project.  But if I knew for sure the final requirements for our project (ie no chance of specification changes/bloat), I would smarten this up.

Anyway, if you end up using/improving this, please let me know.  But I think your dream of not having a mediator for every type of popup is likely to become a nightmare if you pursue it.  I don't see that working out for you unless your project's management can guarantee there will be no functionality bloat.
« Last Edit: July 25, 2010, 11:23:09 by jpwrunyan » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: July 28, 2010, 01:34:31 »

This is also a good approach. It all depends on your application, just how you want to handle this. It is a problem ripe for a utility, but how to make it such that it covers most of the ways people want to handle popups is the problem that needs to be churned on a bit more by someone.

-=Cliff>
Logged
Pages: [1]
Print