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: Resgister multiple views with a single Mediator  (Read 22508 times)
masterkrang
Newbie
*
Posts: 7


View Profile Email
« on: February 10, 2011, 11:31:24 »

Is it crazy to think that I could have a multiple views registered with the same Mediator? For example if I have 10 view classes that are reporting their loading and progress to a progress bar, I'd think that they should be registered with the same Mediator, for example ViewProgressMediator. Also, I keep getting into situations where I wish all classes that subclass a certain class, let's say they subclass LoaderSprite, would it be possible to register all classes that subclass LoaderSprite with a Mediator ViewProgressMediator? These are sort of one in the same question. Right now, the only other alternative I can think of is to create separate Mediators for each View.

Any thoughts?
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: February 12, 2011, 09:52:53 »

You can have 10 instances of the same Mediator registered, each with a separate view component, but you must give the mediator a unique name when you construct it.

So instead of:
:
public function ViewProgressMediator( viewComponent:LoaderSprite )
{
     super(NAME, viewComponent);
}

You'd do something like this:
:
public function ViewProgressMediator( viewComponent:LoaderSprite )
{
     super(NAME+"/"+viewComponent.id, viewComponent);
}

-=Cliff>
Logged
digividpro
Newbie
*
Posts: 5


View Profile Email
« Reply #2 on: June 10, 2011, 02:53:26 »

How do you assign an "id" to a viewComponent instance? In the sample codes I've looked at for view component, the NAME is declared like "public static const NAME:String ='ViewComponentName'." I would be getting the number of views needed from the data source and therefore would need to assign "id" dynamicaly for each required instantiation. Would I declare an "ID" constant and give it a value of something like NAME+'id'? ANd then how would I pass that id to the instantiation? (yes I'm a newbie)
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #3 on: June 11, 2011, 10:15:48 »

There are lots of ways to handle the creation of the ID. The important thing is to understand which way is best for your app.

For instance in the HelloFlash demo[1], the StageMediator's[2] notification handler case for the ApplicationFacade.STAGE_ADD_SPRITE note is where a new HelloSprite is created. It refers to the SpriteDataProxy to find out the next color and id for the sprite, then it registers a HelloSpriteMediator for this HelloSprite just before adding the sprite to the stage.

Is that arrangement right for your app? Not necessarily. To figure out the right approach for your app, three things that need to be considered:

1) Figure out where you're going to keep the next id for each mediated view component that needs to be instantiated multiple times.

This could be kept on a Proxy, the Mediator responsible for instantiating, or mediating the component. Better encapsulation would be to keep it in a class variable on the component itself. You can make the constructor of the component claim the next id then increment it.

The common element of these approaches is that the id is assumed to be important only as a uniquifier to allow us to register multiple mediators.

However, if your view component will have a one-to-one relationship with a particular piece of data for its entire lifetime (for instance, a component to view a specific RSS feed in a tabbed view), then your data may provide a unique id that can be used in the creation of the id for the corresponding component. This leverages the implicit relationship of the view component to its data for more than just a uniquifier. It can set up a communications channel to the specific mediator for data updates its component is interested in.

The proxy could send a note with the feed data in the body of a VIEW_FEED note and the id in the type property of the note. A command could be triggered by this note, create a corresponding view component, set the id and data from the note, then register a new mediator for the component. In the mediator's onRegister, you could then send an ADD_TO_STAGE note that would be heard by a stage or application mediator (or whoever's in charge node of the display list you want to insert this new component into).

Now you have a mediated instance of the feed component in the display list, showing the initial data.

There after, lets say the proxy makes a timed poll of the feed and gets updated data. It could send a FEED_UPDATE note with the feed id in the type and the new data in the body. The mediator for the feed component would be listening for this and if the type property of the note matched the id of its view component, then it would handle the note by setting the data on its view component, otherwise it would ignore it.

2) Figure out where you're going to instantiate the view components.

In HelloFlash this happens in the StageMediator. In the scenario I described at length above, it happens in a Command.

It could also happen in the constructor of the mediator that will mediate the new component. Rather than expect a view component on the constructor of the mediator, have the mediator create the child.

One place it would never happen is a Proxy. The model should in no way ever be tied to the view or controller tiers of the application. You should never see an import in a proxy for something not living in your model package. This makes it portable. In HelloFlash, the next id for the HelloSprite was kept there, to show that application data (relating to the operation of the app), as well as domain data (relating to the data model the app serves) can both live in Proxies. But you'll note that the proxy doesn't know any of the view or controller region actors.

3) Figure out how you're going to get the instantiated component into the view hierarchy.

Usually the top of the view hierarchy is mediated by an application mediator or stage mediator. (Note that stage is specific to Flash as is the term display list, but remember this same logic governs how all PureMVC apps work regardless of language). But the top of the hierarchy isn't necessarily the place to insert something if in order to do so, you have to break encapsulation of the view component by 'reaching down' into it's children.

For instance, if you have an application, and it has a tab navigator inside of which one the children is an accordion, and it is into this accordion that your new child goes, you would want to be sure that accordion component was mediated, and then send the newly created component off a note like ADD_FEED_ACCORDION_CHILD that the FeedAccordionMediator hears and inserts the new component into its child.

That is a far better approch than having the application mediator take the note and try something snarky like: app.tabnav.getChild(2).addChild(viewComponent).

-=Cliff>

[1] HelloFlash wiki: http://trac.puremvc.org/Demo_AS3_Flash_HelloFlash
[2] HelloFlash's StageMediator: http://trac.puremvc.org/Demo_AS3_Flash_HelloFlash/browser/trunk/src/org/puremvc/as3/demos/flash/helloflash/view/StageMediator.as
« Last Edit: June 11, 2011, 10:24:33 by puremvc » Logged
digividpro
Newbie
*
Posts: 5


View Profile Email
« Reply #4 on: June 11, 2011, 01:18:01 »

I think I understood much of that. In any of these scenarios, would it be advantageous to create a vo for each view/component instance? I'm thinking a dataProxy could parse an xml that contained things like titles, copy and paths to images for each view component and assign/store each component's particular data in a corresponding vo, then have a data array hold each vo in the appropriate index/id. When instantiating the mediator/component I could pass the data[id] of the vo. And from then on call a show/hide type function to the already created view mediator/component by its id. Or am I adding an unecessary step or not understanding the vo concept correctly?

The upshot of all this is  to avoid recreating a view once a user has called for it,  since each view loads a set of images that shouldn't be re-loaded/refreshed with every call; just checked to see if it/they have already been created/loaded, then show or create as needed.

something like: for ( var i:uint=0; i<sections.length(); i++ )
         {
            var section:XML = sections[ i ];
            var id:String = section.@id;
                                           var vo:SectionVO = new SectionVO( id,
                                      section.@label,
                                      section.content,

                        section.imagePath );                                  
            data[ id ] = vo;)
}
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: June 12, 2011, 03:45:36 »

Sure, a value object is the most straightforward way to pass data across the tiers of an app. You might want to consider where you place the responsibility for parsing the XML, though. 

Rather than putting the parsing logic in the Proxy, you can put it in the VO itself. Have an XML property that the proxy sets. Then have accessor methods that read and write to the XML structure, but look like typed properties. This is particularly easy in Actionscript with its implicit getter / setter syntax and XML as a native data type.

The nice thing about it is you get to use the powerful XML handling in AS3 but avoid the fat parser that the proxy becomes if you have it rip out the data and set it on a VO with ordinary properties. And once the data is delivered to the view, if you modify (or create more of the same VOs), you don't have to have another big method to take all the values off the VO and put them into XML form before sending them off to the server. As the properties were set in the view, the XML was automagically populated - without the view needing to know anything about the XML structure. The proxy can just pluck the XML and submit it to the service.

For lack of a better name, I call this a SmartVO. See an example of a 'Smart VO' here: http://forums.puremvc.org/index.php?topic=1293.msg5973#msg5973

-=Cliff>
Logged
digividpro
Newbie
*
Posts: 5


View Profile Email
« Reply #6 on: June 18, 2011, 01:24:40 »

You can have 10 instances of the same Mediator registered, each with a separate view component, but you must give the mediator a unique name when you construct it.

So instead of:
:
public function ViewProgressMediator( viewComponent:LoaderSprite )
{
     super(NAME, viewComponent);
}

You'd do something like this:
:
public function ViewProgressMediator( viewComponent:LoaderSprite )
{
     super(NAME+"/"+viewComponent.id, viewComponent);
}

-=Cliff>

I'm still struggling a bit with this: where does  'viewComponent.id' come from? Does this assume the component is instantiated before this mediator and you're somehow passing the .id value with the (viewComponent:LoaderSprite)?

Can I give/pass the id to the mediator to use in its contstructor AND to creates its View?

Like:

:
private var index:String;

public function SectionViewMediator(viewComponent:Object=null, id:String) {
index=id;
super( NAME+"_"+index, viewComponent);
}
and then
:
override public function onRegister():void {
                   sectionView = new SectionView();
sectionView.init( index );
}
Logged
digividpro
Newbie
*
Posts: 5


View Profile Email
« Reply #7 on: June 18, 2011, 03:43:25 »

Sorry for the "run-on" nature of this inquiry. But I've sort of managed to get some of this working, only I can't seem to retrieve/check for the mediator name when I try to assign an index to it.
Since my goal is to have several mediator/view instances of my basic view class, I want to check to see if an instance has been created before instantiating a new one. If a mediator/view instance pair has been created, I just want to "show" it (and hide any others), not re-create it or re-load it's images, etc.

Here's what I'm doing to create a "unique" mediator/view pairing:

in my application mediator I pick up a notification to either show an already created view or create a new mediator/view by executing the following:

:
facade.registerMediator( new SectionViewMediator(body.valueOf(), viewComponent ) );

in the SectionViewMediator:

The constructor is:

:
private var sectionView:SectionView;
private var index:Number;
private var section:Object;
// Initialization:
public function SectionViewMediator(_index:Number, viewComponent:Object=null) {
index = _index;
super( NAME+"_"+index, viewComponent);
trace ("NAME = "+NAME);

}


followed immediatley by:

:
override public function onRegister():void {
trace ("SectionViewMediator Registered");
section = proxy.setSection(index);
//section is a valueObject created in the proxy, stored in an array of valueObjects
sectionView = new SectionView();
sectionView.init(section);

This seems to be creating the appropriate mediator/view instances - passing a valueObject to the view -, but I haven't figured out how to query the facade to "verify" them.

I've tried using "facade.hasMediator(SectionViewMediator.NAME)", but I don't seem to be able to substitute 'NAME+"_"index' in place of NAME to test whether it's been created/instantiated. The query always returns "false", so I'm guessing my new mediator was created, but it doesn't provide a way to check for the specific mediator/view before "deciding" to create a new mediator/view.
Logged
digividpro
Newbie
*
Posts: 5


View Profile Email
« Reply #8 on: June 18, 2011, 04:21:01 »

1000 apologies!!!!


There was a typo in my code above.

The following works:

(within the case statement)
:

var index:Number= body.valueOf()
if (!facade.hasMediator(SectionViewMediator.NAME+"_"+index))
{
facade.registerMediator( new SectionViewMediator(index, viewComponent ) );
}


if the return is "true", I build a new mediator/view, if "false", I will show the already created view.

I can only hope my shenanigans here have helped someone else... :)
Logged
Pages: [1]
Print