FlashVars and Context

derekrosien's Avatar

derekrosien

25 Mar, 2011 10:08 PM

Hi there, I am brand new to Robotlegs ( and absolutely LOVE IT, it has changed the way I think about everything now)...

I saw a thread on FlashVars ( http://knowledge.robotlegs.org/discussions/questions/63-how-to-hand... )

I have one question if anyone can help me out a bit.

So I will get the following first thing in the startUp of the context
var _flashVars:Object = contextView.stage.loaderInfo.parameters;

What is the best technique to set these flashVars into a model?

I was thinking of creating a AppDataModel and storing them there. Then injecting this model wherever I would need to access one of the flashVars throughout the application.

My next thought along this track would be to make a command to set these variables in this model...

I guess my question is:

How do I immediately call a command to do this right at the start of the context? And will this command completely finish and then the context will continue on from there?

Like if I map mediators after this that will inject the AppDataModel, will the command finish and update all the variables it needs to before any other class injects the AppDataModel and the rest of the context does what it needs to, will that have all the flashvars set?

Thanks a lot for the help.

Derek

  1. 2 Posted by derekrosien on 25 Mar, 2011 10:14 PM

    derekrosien's Avatar

    Just created an account on this site now... not sure if I needed to do this first.

  2. 3 Posted by Michal Wroblewski on 25 Mar, 2011 10:26 PM

    Michal Wroblewski's Avatar

    Hi Derek,

    Your thoughts on this are right. Just create Signal/Command something like StartupCommand. Then in that command you can inject AppDataModel and call a method, something like appDataModel.parseFlashVars(flashVarsObject). In that StartupCommand you can do whatever you want to init your app, e.g. init service action to load some data at start or anything else you want.

    Mike

    BTW. Great choice - I mean Robotlegs ;)

  3. Support Staff 4 Posted by creynders on 26 Mar, 2011 06:46 AM

    creynders's Avatar

    Personally I wouldn't create a separate AppDataModel if not necessary and just let the command which is responsible for requesting the flashvars distribute the values to the correct services and models. Also, IMO the model shouldn't be responsible for parsing the values, but should instead expose methods to receive the relevant data.
    Most of the times I have a ConfigureApplicationCommand which pulls in all the relevant configuration data (for example: query string and flashvars) using services, and separate parser classes and subsequently uses that data to map values, set model data et cetera. Obviously you can separate this into several commands, depending on the amount of data, the number of sources and modularity.

    You can call a command directly from the context if you want to ( http://api.robotlegs.org/org/robotlegs/base/CommandMap.html#execute() ) but I wouldn't recommend that though. It's better to map the command to the ContextEvent.STARTUP event (or create your own event, which is dispatched separately)
    In flash code is executed synchronously which means that the code inside the command will execute fully before the framework proceeds to the next statement. However, this is only the case if it doesn't call any asynchronous methods (loading files, calling remote services etc.) So, in your example using flashvars, yes the command would finish execution before the other classes get the AppDataModel injected (if you've mapped everything correctly)
    Bootstrapping and configuring an application is a bit of a trial-and-error thing the first times, a lot can go wrong, but after a few projects you get the hang of it and know the pitfalls.

    I'd strongly recommend to read the best practices documentation thoroughly and browse the various utilities other people have already written. There are many time (and life) savers amongst them (like for instance DeferredCommandQueue)

  4. 5 Posted by derekrosien on 26 Mar, 2011 02:43 PM

    derekrosien's Avatar

    AWESOME AWESOME AWESOME!!! Thanks for the help.

    Love the execute() method!... I see the benefit also of using the ContextEvent.STARTUP event as well...

    One question about the ContextEvent.STARTUP event, would that fire before the code in the context's startup() method? I would think so but I would just like a confirmation.

    And, how does one map a command to this event if most of the mapping is done in the startup()?

    Yes I have read the best practices, first time through it was mostly getting high level... I have it printed off and and have it handy for access as I have heard from a number of people that it is a must read for beginners.

    I am going to create an attempt at this and maybe post some snippets of my classes if you guys could give a quick once over and confirm I am on the right track.

    I am really liking Robotlegs and Signals and yes I completely agree that once I get a few demos and proof of concepts under my belt I will get the hang of the initial setup.

    Thanks again for the help Michał & creynders... It has been a huge help.

    Derek

  5. 6 Posted by derekrosien on 26 Mar, 2011 02:58 PM

    derekrosien's Avatar

    OK this is working perfect!

    AppContext.as

    startup(){
        //Map the model & fire the InitApplicationCommand
        injector.mapSingleton( AppDataModel );
        commandMap.execute( InitApplicationCommand, contextView.stage.loaderInfo.parameters );
        // Continue on setting up the rest of the app
    }
    

    InitApplicationCommand.as

    [Inject] public var _appDataModel:AppDataModel;
    [Inject] public var _commandPayloadObj:Object;
    execute(){
        _appDataModel.setVar( _commandPayloadObj[ "flashVarName" ] );
    }
    

    That worked perfectly!

    creynders, I would still be interested in knowing how to map the InitApplicationCommand to the ContextEvent.STARTUP event and if in fact that is fired before the actual startup() method begins within the context.

    Thanks again guys!!! It is greatly appreciated.

    Derek

  6. Support Staff 7 Posted by creynders on 26 Mar, 2011 03:10 PM

    creynders's Avatar

    You need to dispatch the ContextEvent.STARTUP event yourself (most of the times inside the startup event of the context class)
    Simply put your startup looks like this:

    override public function startup() : void{
        //do not call, since it will dispatch ContextEvent.STARTUP_COMPLETE
        //super.startup()
    
        commandMap.mapEvent( ContextEvent.STARTUP, MapDependeciesCommand, true );
        commandMap.mapEvent( ContextEvent.STARTUP, ConfigureApplicationCommand, true );
        commandMap.mapEvent( ContextEvent.STARTUP, CompleteStartupCommand, true );
    
        eventDispatcher.dispatchEvent( ContextEvent.STARTUP );
    }
    

    In real projects your bootstrapping and configuration sequence will be a lot more complex, since you'll be loading configuration data from xml files, accessing flash vars et cetera.
    Also, I never us a single MapDependeciesCommand, but either split it up in: (small projects)
    MapViewCommand, MapModelCommand, ...
    or if it's a large project with lots of of different functionalities that I want to be able to enable/disable fast:
    BootstrapSomeFunctionalAreaCommand, BootstrapAnotherFunctionalAreaCommand, ...
    Which in turn call their respective MapViewCommand, MapModelCommand, ConfigureSomeFunctionalAreaCommand,...

    All depends on the scale of your project and how flexible you want it to be in terms of scalability, reuse. Another approach would be to use modules, but don't worry about that now, first you need to get the basic hang of this.

  7. 8 Posted by derekrosien on 26 Mar, 2011 03:40 PM

    derekrosien's Avatar

    KICK ASS!!!!

    Thanks again! HUUUUUGE HELP.

    Man such a different way of thinking about it all...Haha I am going to look at all my old code now and just shake my head :)

    BUT, that is good though, cause my app is going to be a big one and I think I am down the right track with learning and implementing Robotlegs and Signals.

    Just a brief rundown of my thoughts on initializing…

    • load flashvars
    • load locale bundle(s)
    • configure AMF connection
    • make initial AMF call to get user profile (based on server id passed in through flashvars)
    • based on user profile received, load xml config file based on the user’s role/permissions ( which will enable modules in the app )
    • load external CSS modules for branding and role settings within the user profile
    • do any remaining bootstrapping, mapping all the views, mediators, commands, etc.
    • see if there is a jump to a specific section using SWFAddress and go to that section, or load the home page

    I guess the “do any remaining bootstrapping” part could/should be moved higher up in that sequence?

    What I am trying to start with is to hammer out these different tasks in test apps to get an idea of how these sequences will work… Then double back and combine them all into one startup sequence in the main app and setup a navigation system to go between the different modules.

    I really like your idea of the modular commands rather than one massive initCommand though, will have to look into that.

    What I was also thinking of doing was to handle the login on the Java side of things… This app may exist within a client’s portal so using their single sign on to pass a session id into the app then when requesting the user module, just pass that session id so that the server knows which user profile to return to the app and that will get things moving.

    What do you think of that sequence? Obviously that question is stretching the meaning of this post a bit, but thought I would ask… You have already been a huge help so don’t feel obligated to reply to that. Just thought I would run all that by you.

    Derek

  8. Support Staff 9 Posted by creynders on 27 Mar, 2011 11:07 AM

    creynders's Avatar

    You'll really need to use modules then, here's a tutorial:
    http://knowledge.robotlegs.org/discussions/resources/12-dynmodules-...
    It has the advantage that each part/module can be tested separately, so you can develop your app in functional units.

    I'm a bit worried about the security of this app though, especially:
    'load xml config file based on the user’s role/permissions' That's something that can REALLY easily be hacked.
    All authorization should happen server-side, so you'll have to make sure to check the user's permissions on each service call as well and not only rely on the front-end for that, but maybe you're aware of that. Just thought to warn you.

    As for the bootstrapping sequence, that's exactly as I would do it too. Just make sure either to use a finite state machine or some kind of iterator to keep track and serve the next step in sequence. Never patch commands (meaning: CommandA executes and calls CommandB, which executes and calls CommandC) it will become a horrible mess.

  9. Support Staff 10 Posted by creynders on 27 Mar, 2011 11:35 AM

    creynders's Avatar

    Another thing, avoid injecting native types like Object, because it will get you into a lot of trouble. Always wrap them up in a VO. Or use named injection, but I prefer to use a VO.

    The way I do it is, I load my config data in a service, which uses a parser to populate a VO with all config data, then sends the VO with an event to the framework. The receiving command runs through the VO's properties and maps values, sets model and/or service properties.

    And one last tip: I haven't seen other people use this yet, but I think it's REALLY convenient: use custom namespaces for the configurable properties of your models.
    Something like this

    //configurable.as
    public namespace configurable = 'be.creynders.appname.ns.CONFIGURABLE'
    
    //SomeModel.as
    configurable function setSomeProp( value : String ) : void {
    }
    
    //ConfigCommand
    [Inject] public var model : SomeModel;
    
    public function execute():void{
        model.configurable::setSomeProp( 'foo' );
    }
    

    It has the advantage that you can't accidently call model.setSomeProp( 'foo' ) unless if you deliberately import the namespace. Also, that method will not show up in your IDE's intellisense (unless you imported the namespace). And it neatly "marks" that method as being used only during the configuration phase. In other words it prevents you from reusing that method outside the configuration phase.

  10. 11 Posted by derekrosien on 27 Mar, 2011 12:07 PM

    derekrosien's Avatar

    OK cool. thanks again for the info.

    Yeah we do a lot of authorization on the back end with every call but I would double check this for sure.

    The modules for sure... I will take a look at that tutorial. And your comments make total sense about the VOs ( which will be good if those data sources ever change ).

    I have looked into namespaces before, but to be honest I think they are still a bit foreign to me... I will try and take a look at them again to see if I can make sense of them.

    Thanks again for all the help and advice. It really helps me out a LOT!

    Derek

  11. derekrosien closed this discussion on 30 Mar, 2011 07:07 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac