tag:robotlegs.tenderapp.com,2009-10-18:/discussions/robotlegs-2/12476-rl2-bootstrap-command-chainRobotlegs: Discussion 2015-05-11T11:31:18Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112014-10-24T11:41:23Z2014-10-24T11:41:23ZRL2 Bootstrap command chain<div><p>First of all, let's clarify what should happen in your
BootstrapApplicationCommand.</p>
<p>If by bootstrapping you mean just the mappings of Models,
Mediators, Services and Commands, the easiest way to do that is to
have config classes for each category of mappings and tell the
Context to use them for configuration.</p>
<p>For example a MediatorsConfig would look like this:</p>
<pre>
<code>public class MediatorsConfig implements IConfig
{
[Inject]
public var mediatorMap:IMediatorMap;
public function configure():void
{
mediatorMap
.map(SomeView)
.toMediator(SomeMediator);
}
}</code>
</pre>
<p>Note that MediatorsConfig implements <strong>IConfig</strong>
and has a <strong>configure()</strong> method which will be called
automatically by the context. You put your mappings inside the
configure().</p>
<p>A ControllersConfig could look like this:</p>
<pre>
<code>public class ControllersConfig implements IConfig
{
[Inject]
public var commandMap:IEventCommandMap;
public function configure():void
{
commandMap
.map(SomeEvent.SOME_TYPE, SomeEvent)
.toCommand(SomeCommand);
}
}</code>
</pre>
<p>When you create and configure your context, you let the context
use your custom configurations:</p>
<pre>
<code>_contextView = new ContextView(view);
_context = new Context();
_context.install(MVCSBundle);
//add your config classes in the needed order:
_context.configure(ModelsConfig, MediatorsConfig, ServicesConfig, ControllersConfig);
_context.configure(_contextView);</code>
</pre>
<p>That is all you need for a simple configuration. Say more about
your workflow, in case that kind of configuration is not sufficient
for you.</p>
<blockquote>
<p>In RL1 there was a ContextEvent. In RL2 there isn't anymore.</p>
</blockquote>
<p>The robotlegs 2 Context has a lifetime, aka lifecycle: it is
created, used, then destroyed (or not).<br>
The rl2's Context creates a LifeCycle for itself (<a href=
"https://github.com/robotlegs/robotlegs-framework/blob/master/src/robotlegs/bender/framework/impl/Context.as#L432">https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...</a>
) and raises a number of events (LifecycleEvent) that you can hook
on to.<br>
<a href=
"https://github.com/robotlegs/robotlegs-framework/blob/master/src/robotlegs/bender/framework/readme-lifecycle.md">
https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...</a></p>
<p>Context's lifecycle hooks are:</p>
<pre>
<code>beforeInitializing
whenIntitializing
afterIntializing
beforeSuspending
whenSuspending
afterSuspending
beforeResuming
whenResuming
afterResuming
beforeDestroying
whenDestroying
afterDestroying</code>
</pre>
<p><strong>afterIntializing</strong> is a very useful hook, when
you want to make sure that something happens after the Context has
been fully initialized and all mappings created. That way you can
avoid running into race conditions. To use it, you just create a
handler like this:</p>
<pre>
<code>_context = new Context();
// A handler to run after initialization:::
_context.afterInitializing(yourAfterInitializingHandler);
_context.install(MVCSBundle);
_context.configure(ModelsConfig, MediatorsConfig, ServicesConfig, ControllersConfig);
_context.configure(_contextView);</code>
</pre>
<pre>
<code>private function yourAfterInitializingHandler ():void
{
//do something
}</code>
</pre>
<p>If you want to trigger a Command from within one of your config
classes, you can do it like in your example, you inject a shared
event dispatcher into your config class, you map a custom event to
a command inside the configure() method and then dispatch the event
on the shared event dispatcher. The difference is that you use a
custom event instead of context's event.</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112014-10-24T12:30:11Z2014-10-24T12:30:11ZRL2 Bootstrap command chain<div><p>Thanks Ondina,</p>
<p>the flow of configuring the mappings as single configs is
great.<br>
_context.configure(ModelsConfig, MediatorsConfig, ServicesConfig,
ControllersConfig);<br>
are them configured one after the other?</p>
<p>What could be a further step for bootstrapping?</p>
<p>I have anothzer question. Is there a good tutorial explaining an
example like this?<br>
<a href=
"https://github.com/robotlegs/robotlegs-demo-TodoList">https://github.com/robotlegs/robotlegs-demo-TodoList</a><br>
I need someone/something explaining how to use signals, behaviors
and actions. Most people are developing in the way from that
example and i would like to learn it but I dont know here to start.
I dont really know why and how to seperate behaviors and link the
to different interfaces related to the view. Until now I just have
several views and a mediator of it. but this seems not to be the
best way. but for understanding why I need some detailed
explanations.</p>
<p>I hope you undertsand what I mean</p></div>iamabletag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112014-10-24T16:09:33Z2014-10-24T16:09:33ZRL2 Bootstrap command chain<div><p>You're welcome :)</p>
<blockquote>
<p>are them configured one after the other?</p>
</blockquote>
<p>Yes.</p>
<blockquote>
<p>What could be a further step for bootstrapping?</p>
</blockquote>
<p>Hmm. I don't know. It depends on your needs. What else do you
need to do there?</p>
<blockquote>
<p>I have anothzer question.</p>
</blockquote>
<p>It is always better to open a new discussion, if the question
has nothing to do with the current discussion :)</p>
<blockquote>
<p>Is there a good tutorial explaining an example like this?</p>
</blockquote>
<p>I don't know if the following links are what you need. Anyway
here they are:</p>
<p><a href=
"http://justinjmoses.wordpress.com/2011/08/07/ui-mediation-sucks-mediate-behaviours-not-views/">
http://justinjmoses.wordpress.com/2011/08/07/ui-mediation-sucks-med...</a></p>
<p><a href=
"http://justinjmoses.wordpress.com/2011/07/07/whats-the-deal-with-signals/">
http://justinjmoses.wordpress.com/2011/07/07/whats-the-deal-with-si...</a></p>
<blockquote>
<p>I need someone/something explaining how to use signals,
behaviors and actions.</p>
</blockquote>
<p>I can understand very well your need for guidance.<br>
I would like to help you, but it takes a lot of time to explain
everything in detail, and sadly I don't have that much time. I
think that you need to understand the basic principles of rl and
MVCS and how everything works using events first. Have you read the
Best Practices yet? And Joel's tutorials? Or, better, the rl book?
They are for rl1, but still a good start in understanding rl. Do
you need links to the tutorials / book?</p>
<p>I can't promise anything (!!), but if I get a chance next week,
I'll try to explain how to use interfaces to mediate behaviours.
You should do some reading (best practices, rl book) in the
meantime ;)</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112014-10-28T14:43:22Z2014-10-28T14:43:22ZRL2 Bootstrap command chain<div><p>I've put together an example (AIR 3.9, FlashBuilder 4.6) this
morning. See attachment.</p>
<p>There is a MorphogenView mediated by MorphogenMediator. I named
it Morphogen, because it controls the type and position of shapes
in different sub-views.</p>
<p>MorphogenView holds</p>
<ul>
<li>
<p>3 sub-views:</p>
<ul>
<li>MonomorphicViewOne</li>
<li>MonomorphicViewTwo</li>
<li>PolymorphicView</li>
</ul>
</li>
<li>
<p>a set of buttons to control the creation, deletion and rotation
of shapes in the 3 sub-views</p>
</li>
<li>
<p>and a TextArea for logging</p>
</li>
</ul>
<p>Monomorphic - because it creates only one shape<br>
Polymorphic - because it creates 2 (or more) shapes.</p>
<p>The 3 sub-views extend a BaseShapeView. Each of the 3 sub-views
implements a different set of interfaces.</p>
<p>The interfaces are:</p>
<ul>
<li>
<p>IMakeCircles</p>
</li>
<li>
<p>IMakeSquares</p>
</li>
<li>
<p>IRotateShapes</p>
</li>
<li>
<p>IResetShapes</p>
</li>
</ul>
<p>As their names suggest, they offer an API for different
functionalities, that are the methods of BaseShapeView.</p>
<ul>
<li>
<p>MonomorphicViewOne implements IMakeSquares, IRotateShapes,
IResetShapes</p>
</li>
<li>
<p>MonomorphicViewTwo implements IMakeCircles, IRotateShapes,
IResetShapes</p>
</li>
<li>
<p>PolymorphicView implements IMakeSquares, IMakeCircles,
IRotateShapes, IResetShapes</p>
</li>
</ul>
<p>Because of the interfaces that are implemented, each view
exhibits a different/specific or a shared behaviour</p>
<ul>
<li>
<p>MonomorphicViewOne's special behaviour is to make squares</p>
</li>
<li>
<p>MonomorphicViewTwo's special behaviour is to make circles</p>
</li>
<li>
<p>PolymorphicView's behaviour is to make squares and circles</p>
</li>
</ul>
<p>All 3 views are capable to rotate themselves and to delete the
contained shapes, because they all implement those behaviours
(IRotateShapes, IResetShapes)</p>
<p>From within the click event handlers of the buttons in
MorphogenView a custom event, that I named BehavioursEvent, will be
dispatched.<br>
Say, the "make circles" button is clicked. This will be translated
into a request, BehavioursEvent.MAKE_CIRCLE_REQUESTED.<br>
MorphogenMediator will re-dispatch the request (event).</p>
<p>The sub-views should be able to react to that request and to do
their thing (apply the corresponding behaviour == draw circles). In
fact, only the views capable of making circles should react to the
event. To achieve this, a MakeCirclesMediator, injected with an
IMakeCircles, will let the views that implement IMakeCircles call
makeCircle() method. As a consequence, only MonomorphicViewTwo and
PolymorphicView will draw a circle. MonomorphicViewOne won't be
bothered by the request.</p>
<p>If MorphogenView would request squares
(BehavioursEvent.MAKE_SQUARE_REQUESTED), only MonomorphicViewOne
and PolymorphicView would react, because their behaviour is
mediated by MakeSquaresMediator, which is injected with
IMakeSquares.</p>
<p>When MorphogenView sends a ROTATE_SHAPE_REQUESTED event, all
views will react to it, because the behaviour is mediated by
RotateShapesMediator, which is injected with an IRotateShapes.</p>
<p>PolymorphicView has also a Mediator for itself,
PolymorphicMediator. I only created it to show you that it is
possible to have it next to the "behavioural" mediators. At the
moment only PolymorphicMediator is listening for LoggerEvent.</p>
<p>It might sound complicated, but it is not. You should run the
example in order to better understand the explanations.</p>
<p>I intentionally created 2 separates behaviours, like
IMakeCircles and IMakeSquares, just for the sake of an example. In
a real application you would want to abstract those behaviours even
further. My example shows only one of the many possible use cases
of mediating behaviours instead of concrete views.</p>
<p>So, a behaviour can be a certain functionality or a set of
functionalities, an action or a reaction, that a component may
display.</p>
<p>I hope that helps.</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112015-04-21T13:01:16Z2015-04-21T13:01:16ZRL2 Bootstrap command chain<div><p>Hey Ondina,</p>
<p>sorry for that late reply. I wasn't programming for almost half
a year.<br>
I had some time now to have a look at your example project.<br>
First of all thank you very much for that effort.<br>
Now I understand why and how to mediate against behaviors.<br>
If I understand right: Someone is dispatching an event for a
specific behavior. The Behavior mediator is listening for it. he
has the injected interface for the behavior calling a method. the
view implements that interface and its behavior. so the mediator
and the view is decoupled. Am I right?</p>
<p>What I am missing in your project is the handling of application
data.<br>
How to handle models in RL2. In the past I had an actor dispatching
an event. the listening mediator injects the model and changes the
view.<br>
I've just read injecting the model into the mediator is not the
best way.<br>
Do you have any best practice how to handle changed model data and
how to change the view based on that data?</p></div>iamabletag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112015-04-21T14:13:58Z2015-04-21T14:13:58ZRL2 Bootstrap command chain<div><p>I also have problems in dispatching events from the model.
Injecting IEventDispatcher doesnt work. The instance is always
null</p></div>iamabletag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112015-04-21T14:37:54Z2015-04-21T14:37:54ZRL2 Bootstrap command chain<div><p>OK second problem is solved by letting the injector instatiate
the model</p>
<p>var model:Model = injector.instantiateUnmapped(Model);<br>
injector.map(Model).toValue(model);</p></div>iamabletag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112015-04-22T15:56:21Z2015-04-22T15:59:11ZRL2 Bootstrap command chain<div><p>Hi,</p>
<p>You're welcome.</p>
<p>How is life without programming? ;)</p>
<p>I've modified the previous example in order to show you how to
dispatch events from a model.</p>
<p>I've added a StatisticsView coupled with a
StatisticsMediator.<br>
When a shape is added or removed from the views, a StatisticsEvent
is dispatched (from within the BaseShapeView) with a payload
containing a ShapeVO. The ShapeVO has properties like shapeId,
shapeSize, shapeColor...<br>
MakeCirclesMediator and MakeSquaresMediator are listening to the
events dispatched by the views, and are redispatching them in order
to trigger commands.</p>
<p>The commands, AddElementCommand and RemoveElementCommand are
mapped to the StatisticsEvent .ELEMENT_ADDED and respectiveley to
StatisticsEvent . ELEMENT_REMOVED. They are accessing the
StatisticsModel's methods addElement() and removeElement(). The
StatisticsModel does a rudimentary math operation and then it
dispatches a StatisticsEvent.STATISTICS_RESULTS with a payload.</p>
<p>The StatistcsMediator, which is listening to this event, passes
the payload of the event on to the StatisticsView, which is
populating a datagrid and 2 input fields with the results. The
datagrid is showing the ids, names and colors of the shapes, and
the 2 input fields the math results.</p>
<p>For example:</p>
<ol>
<li>
<p>BaseShapeView.makeShape-> dispatchEvent(new
StatisticsEvent(StatisticsEvent.ELEMENT_ADDED, shapeVO));</p>
</li>
<li>
<p>MakeCirclesMediator.onElementAdded -> dispatch(event);</p>
</li>
<li>
<p>AddElementCommand -> statisticsModel.addElement(event.payload
as ShapeVO);</p>
</li>
<li>
<p>StatisticsModel -> dispatcher.dispatchEvent(new
StatisticsEvent(StatisticsEvent.STATISTICS_RESULTS,
doSomeMath()));</p>
</li>
<li>
<p>StatisticsMediator.onStatsticsResults(event:StatisticsEvent)-
> view.onStatisticsResults(event.payload);</p>
</li>
<li>
<p>StatisticsView->onStatisticsResults ->
statisticsGrid.dataProvider = payload["collection"];</p>
</li>
</ol>
<p>I hope my explanation is clear enough. It will be easier to
understand, if you run the application.</p>
<p>Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112015-04-23T15:11:35Z2015-04-23T15:11:35ZRL2 Bootstrap command chain<div><p>Thanks Ondina</p>
<p>I understand that but why does StatistcsMediator not relates to
an interface?<br>
As I learned it is better to mediate behavior instead of views.</p></div>iamabletag:robotlegs.tenderapp.com,2009-10-18:Comment/350601112015-04-24T12:30:12Z2015-04-24T12:30:12ZRL2 Bootstrap command chain<div><blockquote>
<p>I understand that but why does StatistcsMediator not relates to
an interface?</p>
</blockquote>
<p>Because I used it to answer your question about how to dispatch
events from models. It was just an example, and there was no need
for an interface.</p>
<blockquote>
<p>As I learned it is better to mediate behavior instead of
views.</p>
</blockquote>
<p>There is no better or worse, it all depends on what you need to
achieve. In other words, it depends on the nature and overall
design of your application.</p>
<p>Of course interfaces are cool, but using interfaces does not
necessarily and automatically guarantee high quality of the code.
There are good APIs and there are bad APIs. Just saying;)</p>
<p>When you are mediating interfaces, you have to take into account
the way mediators react to events. If several views implement the
same interface, every time an event has been dispatched, the
mediator will react to it. So, for example, several views implement
an interface ICleanUp with a method cleanUp(), which resets the
input fields in the views.<br>
An event dispatched by a deleteButton is listen to by a
CleanUpMediator, which then lets the view call its cleanUp()
method. As a consequence, every single view in your application
that implements ICleanUp will delete the contents of their input
fields. That's handy and that's probably exactly what you're after.
But, maybe there are other cases where you wouldn't want a certain
view to always react to a general clean up request...</p>
<p>Other things to consider<br>
A view may need to exhibit a certain behaviour, thus it implements
the corresponding interface. But, the view will need to implement
all of the methods declared in that interface, even if it needs
just one of them.<br>
A view may also end up implementing lots of interfaces. Depending
on how big and complex your application will be, or on how you
design it, or on the level of granularity of your views, there
might be lots and lots of interfaces representing behaviours.
You'll have to ponder whether it is a desired effect to have lots
of mediators for lots of interfaces, or not.</p>
<p>All I'm saying with this is that if you decide that your
application would benefit from mediating behaviours in form of
interfaces, you need to know what to expect from such an approach.
You should try to find the design pattern or approach that will fit
your application's needs, not vice versa.</p>
<p>I hope everything is clear now, and you can start experimenting
with mediation of behaviours :)</p></div>Ondina D.F.