tag:robotlegs.tenderapp.com,2009-10-18:/discussions/robotlegs-2/13003-inject-models-into-specific-purpose-viewRobotlegs: Discussion 2015-10-28T15:48:51Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-01T16:23:14Z2015-08-19T21:05:55ZInject model(s) into specific purpose view<div><p>Another thought that just crossed my mind, perhaps there could
be a model that deals specifically with these AddRecord views? Then
when settings are changed elsewhere in the app, this central model
could be updated by other models and be fed to the necessary views
in a read-only manner?</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-02T14:31:01Z2015-07-02T14:31:01ZInject model(s) into specific purpose view<div><p>If you don't mind the tight coupling of views and models, then
yes, inject the models into your views. The question is, how are
you going to update the views with the changed model's data, since
the views cannot listen to events dispatched on the shared event
dispatcher? Or are you talking about "bindable" model's data like
in the other discussion?</p>
<p>Have you looked at the Presentation Model already?</p>
<p>Regarding your "central model" :<br>
I used a similar approach in one of my real projects where I had to
deal with a great amount of lists used in different parts of my
app. My 'central model' is just holding a list of models, gets an
instance of a required model and returns its data to a command.<br>
I've uploaded a mini-project that I used for experimenting with
mediated lists :</p>
<p><a href="https://github.com/Ondina/robotlegs-bender-mediated-lists">https://github.com/Ondina/robotlegs-bender-mediated-lists</a></p>
<p>Each dropdownlist extends a base view and it is mediated by a
ListMediator. The base view implements an IListView with 2 getters
and setters for a listId and a listDataProvider.<br>
The only thing this mediator does is requesting a data provider for
the list and reacting to changes made to the list's model.</p>
<pre>
<code>mediatorMap.map(IListView).toMediator(ListMediator);</code>
</pre>
<p>Mediator</p>
<pre>
<code>[Inject]
public var view:IListView;
override public function initialize():void
{
addContextListener(ListDataProviderEvent.LIST_DP_CHANGED, onListDPChanged, ListDataProviderEvent);
dispatch(new ListDataProviderEvent(ListDataProviderEvent.LIST_DP_REQUESTED, view.listId));
}
private function onListDPChanged(event:ListDataProviderEvent):void
{
if(event.listId == view.listId)
view.listDataProvider = event.listDataProvider;
}</code>
</pre>
<p>Command</p>
<pre>
<code>public class RequestListDataProviderCommand
{
[Inject]
public var event:ListDataProviderEvent;
[Inject]
public var model:ListDataProviderModel;
[Inject]
public var dispatcher:IEventDispatcher;
public function execute():void
{
dispatcher.dispatchEvent(new ListDataProviderEvent(ListDataProviderEvent.LIST_DP_CHANGED, event.listId, model.getModel(event.listId)));
}
}</code>
</pre>
<p>Model:</p>
<pre>
<code>public class ListDataProviderModel
{
[Inject]
public var injector:IInjector;
private var models:Object = {"shapes": ShapesModel, "users": UsersModel, "colors": ColorsModel};
public function ListDataProviderModel()
{
}
public function getModel(value:String):ArrayCollection
{
var model:* = injector.getInstance(models[value]);
return model.data;
}
}</code>
</pre>
<p>A disadvantage of this approach is that you need to check the id
of the list in the mediator and the model. But, other than that it
works well.</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-02T15:41:51Z2015-08-19T21:05:55ZInject model(s) into specific purpose view<div><p>The views are short lived (they're actually instances of the
windows we worked on a few weeks ago!), so they would get their
data from the model when opened. While it's not impossible, it's
unlikely that a user would update application settings elsewhere
while having this window view open. So my views depend dynamically
on the application state, but in a static sort of way, if that
makes sense? i.e. they only need to check data from the model when
they are created.</p>
<p>I have read about the presentation model and I can definitely
see it applying here. The one thing that jumps out at me is 90% of
the view's data and logic is self contained. It needs about 3 lists
to display data, and 5 or so settings that determine behavior.
Looking at your example I see a few places I could component out
the view, like you did with specific dropdowns, as those are the
pieces that depend on external data. Would every "presenter" need a
mediator and a model? Some I think would only need models, but that
is again tight coupling (although kind of the point of presentation
model, right?). Finally, would it make sense to compile these
presenters into one "regular" Robotlegs view? What about collecting
all of the pieces of data into one centralized object?</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-02T16:37:45Z2015-07-02T16:37:45ZInject model(s) into specific purpose view<div><blockquote>
<p>they only need to check data from the model when they are
created.</p>
</blockquote>
<p>Oh, alright, if the models are just a sort of configs that the
views need when they are added to the stage, then injecting them
into views (or their mediators) falls into the category of
'appropriate coupling' :) Especially if you make them read-only and
inject them as interfaces as you intended..</p>
<blockquote>
<p>Would every "presenter" need a mediator and a model?</p>
</blockquote>
<p>You either use a Mediator or a PresentationModel, not both.</p>
<blockquote>
<p>Some I think would only need models, but that is again tight
coupling (although kind of the point of presentation model,
right?).</p>
</blockquote>
<p>Well, with the mediator pattern the view doesn't have any
reference to its mediator == no coupling, whereas with the
presentation model the view is aware of the model == coupling.</p>
<blockquote>
<p>Finally, would it make sense to compile these presenters into
one "regular" Robotlegs view?</p>
</blockquote>
<p>Don't know what you mean.</p>
<blockquote>
<p>What about collecting all of the pieces of data into one
centralized object?</p>
</blockquote>
<p>This is also unclear. Do you mean collecting the data from the
view or are you referring to the 'central model' from before?</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-02T18:03:06Z2015-08-19T21:05:55ZInject model(s) into specific purpose view<div><p>It's pretty hard to communicate directly what I mean through
text. I created an image file to exemplify dependencies between
components and external data. Let me know if you find it unclear.
What I'm thinking is either the entire window gets the read-only
interfaced models or the components get broken down and data
dependencies get fed to the individual presenters (maybe through
data binding?). Could you give an example on how to implement a
read-only interface and use it with an already existing model in
the application?</p>
<blockquote>
<p>Finally, would it make sense to compile these presenters into
one "regular" Robotlegs view?</p>
</blockquote>
<p>What I mean is these components/presenters all live in a Window,
could this top level window be treated as a view not a presenter?
All of the application state logic would be taken care of in the
components.</p>
<blockquote>
<p>What about collecting all of the pieces of data into one
centralized object?</p>
</blockquote>
<p>The entire view functions as a "form" of sorts. The data
selected and entered has to be collected and sent to the framework
at some point, but the window does not need any knowledge of this
and needs to reset on submit.</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-02T18:03:53Z2015-08-19T21:05:55ZInject model(s) into specific purpose view<div><p>Seems as if the file did not upload.</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-03T11:37:08Z2015-07-03T11:37:08ZInject model(s) into specific purpose view<div><p>Thanks for the image. It is indeed easier to understand what you
mean by looking at it.</p>
<p><strong>The Window</strong></p>
<blockquote>
<p>What I'm thinking is either the entire window gets the read-only
interfaced models or the components get broken down and data
dependencies get fed to the individual presenters (maybe through
data binding?). What I mean is these components/presenters all live
in a Window, could this top level window be treated as a view not a
presenter? All of the application state logic would be taken care
of in the components.</p>
</blockquote>
<p>Yes, that's right, Winow's only raison d'être should be to
show a content in popup manner and to behave nicely when it's
closed ( GC&Co ) . It is just a layout container. Being a top
level component, like the main WindowedApplication, it can also
serve as a contextView in case you want to build a separate Context
in this Window ((but it doesn't have to), as I illustrated in my
example on github (robotlegs-bender-open-close-window).<br>
So, the Window doesn't necessarily need a Model.</p>
<p>To be continued..</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-03T14:42:59Z2015-07-03T14:42:59ZInject model(s) into specific purpose view<div><p>What I get from your uploaded image is that the Window contains
a Navigation (button bars) and several Views contained in something
like a ViewStack. I would create a NavigationView mediated by a
NavigationMediator and add the NavigationView to the Window. (
please excuse the names of these classes and of those I'll be using
further down)</p>
<p>Now, let's assume that what I see in the picture is one of the
Views in that ViewStack. I'll call it ScoreCalculatorView and its
mediator ScoreCalculatorMediator.<br>
Let's say the data that we will send to a database is the following
(inspired by your VOs from our previous discussion):<br>
playerName, playerAge, playerGender, playerPreferedColor,
playerScore, playerAvatar belonging to a PlayerVO, and teamName,
teamScore belonging to a TeamVO - this is data that 'leaves' the
view</p>
<p>playerName, playerAge and playerGender will be saved in a
PlayerPerson db table, playerPreferedColor -> PlayerPreferences,
playerScore -> Scores and so on.<br>
PlayerPreferences has just playerId, colorId and other things ids
like prefered food, book, music, Scores has playerId and score,
Teams has teamId, teamName, theamScore, playerId etc.</p>
<p>The ScoreCalculatorView will contain:<br>
A dropdownlist for playerName, a NumericStepper for playerAge,
check boxes for playerGender, a numeric stepper for playerScore, a
numeric stepper for teamScore, a dropdown for colors, one for
avatars, and a list of teams.</p>
<p>The dropdowns could get their dataprovider as we already
discussed (by mediating each dropdown). This is data that 'enters'
the view. ScoreCalculatorView is not interested in the Models of
those dropdowns. ScoreCalculatorView's role is to collect data from
the different inputs.<br>
Just for fun, if the player chooses the male check box, the list of
colors will filter out womanly colors :P and the playerScore will
be set depending on the combination of chosen color, avatar, gender
and age. The team score will also change depending on player's
score.</p>
<p>So, we deal with at least 2 Models: Player and Team. Because you
like bindings, you can make the VOs bindable, and use 2-way
bindable input elements like so:</p>
<pre>
<code>TextInput id="playerName" text="@{playerVO.playerName}"
TeamListView id="teamList" selectedItem="@{teamVO.teamName}"
....</code>
</pre>
<p>On submit button click:</p>
<pre>
<code>[Bindable]
public var vo:CompoundVO = new CompoundVO();
[Bindable]
public var playerVO:PlayerVO = new PlayerVO();
[Bindable]
public var teamVO:TeamVO = new TeamVO();
protected function submitButton_clickHandler(event:MouseEvent):void
{
vo.playerVO = playerVO;
vo.teamVO = teamVO;
dispatchEvent(new CompoundEvent(CompoundEvent.UPDATE_MODEL_REQUESTED, vo));
}</code>
</pre>
<p>The CompoundVO</p>
<pre>
<code>[Bindable]
public class CompoundVO
{
public var playerVO:UserVO;
public var teamVO:TeamVO;
public function CompoundVO()
{
}
}</code>
</pre>
<p>Instead of a compound vo you can of course use an object of your
choice to hold the 2 (or more) vos.</p>
<p>In the command that gets triggered by the event (redispatched by
the mediator) you can pass the playerVO to the PlayersModel, the
teamVO to the TeamsModel in order to update them and also call a
service to send the data to your backend db.<br>
If you're using a list of players and teams in other views, they
will get updated due to their ListMediator from the previous post
who would listen to update events from the changed models.</p>
<p>Of course you can create a model for the ScoreCalculatorView, if
you need to keep track of view's state or some view specific data,
other than the players and teams. I can't say from just looking at
your drawing if there is a need for a separate model or not.</p>
<p>To conclude: the window holds the stack of views. The views are
mediated. The components that serve as a way to compose view's data
( the dropdowns in our example) get their data independently of
their parent view, i.e. ScoreCalculatorView. ScoreCalculatorView is
managing the relations between its components, i. e. a selectedItem
in a dropdown affects another dropdown's filter options or a
certain choice is used in an algorithm to calculate a score. Then
the final role, to collect data into an appropriate format (in my
case as vos) and send it to its mediator via an event to be
redispatched. Ah yes, and to clean up after itself when the window
gets closed ;)<br>
If some actions in the ScoreCalculatorView should have an effect on
other views, this can happen through events that the mediator can
redispatch.</p>
<blockquote>
<p>Another thought that just crossed my mind, perhaps there could
be a model that deals specifically with these AddRecord views? Then
when settings are changed elsewhere in the app, this central model
could be updated by other models and be fed to the necessary views
in a read-only manner?</p>
</blockquote>
<p>Maybe you had a Model in mind that would gather the player and
team data from the ScoreCalculatorView in my example? So you'd
inject it into another view to access the player model and team
model that were modified in ScoreCalculatorView? And this other
view would maybe modify a game model, also contained in that
central model?<br>
I wouldn't do that. Firstly, a central model that needs to be
always updated by other models can be hard to manage, and secondly,
such a model would be really large and would contain models of no
interest to some views.<br>
But maybe you had something else in mind.</p>
<p>Before talking about presentation model, I would suggest to try
to use the approach illustrated above, or to tell me why do you
think it wouldn't work.<br>
What are the dependencies that the ScoreCalculatorView would need
besides the dataproviders for the dropdowns? You mentioned</p>
<blockquote>
<p>It needs about 3 lists to display data, and 5 or so settings
that determine behavior.</p>
</blockquote>
<p>What kind of settings? Something like</p>
<ul>
<li>
<p>if user is older than 42, use fontSize=18 pt</p>
</li>
<li>
<p>if user is admin, show delete button</p>
</li>
<li>
<p>if view is CompoundFourView ( after clicking on button 4 from
buttonbar) use dropdown filter?</p>
</li>
</ul>
<p>I would inject a ViewBehaviourModel into the mediator and pass
it to the view on initialize. But you can inject it into the view,
if you wish.</p>
<p><strong>A read only model</strong>:</p>
<pre>
<code>public class UsersModel implements IReadUser, IAddUser
.... the methods are as in the example on github
// interfaces
public interface IReadUser
{
function get data():ArrayCollection;
}
public interface IAddUser
{
function addItem(value:UserVO):void;
}</code>
</pre>
<pre>
<code>injector.map(IReadUser).toSingleton(UsersModel);
injector.map(IAddUser).toSingleton(UsersModel);</code>
</pre>
<p>and then you inject them like this<br>
[Inject] public var userModel:IReadUser;</p>
<p>or like so</p>
<p>[Inject] public var userModel:IAddUser;</p>
<p>depending on what you need</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-06T17:06:28Z2015-08-19T21:05:55ZInject model(s) into specific purpose view<div><blockquote>
<p>What kind of settings? Something like</p>
<p>if user is older than 42, use fontSize=18 pt</p>
<p>if user is admin, show delete button</p>
<p>if view is CompoundFourView ( after clicking on button 4 from
buttonbar) use dropdown filter?</p>
</blockquote>
<p>Yes, these are similar to the examples you provided. In the
context of the same tournament example, let's say that there are
different divisions a team can be in, (in American NCAA basketball
there are Divisions I, II, III for example), but this depends on if
you wanted the tournament to use divisions or not -- a boolean
value. This is a setting in the tournament model, and the divisions
list is external data passed to a dropdown from the DivisionsModel.
If the tournament doesn't use divisions, there is no need to show
the dropdown, or maybe you want to set enabled to false.</p>
<pre>
<code>if (tournament.useDivisions) {
divisions_dd.visible = true;
}
\\ Or perhaps more simply
<components:DivisionsListView visible={tournament.useDivisions} ... /></code>
</pre>
<p>The divisions list is like in your mediated list view example,
easy as pie. What about getting the useDivisions setting? Right now
I have the window's mediator request config data which is fine, but
I feel like I'm doing all this separation and wiring and not really
getting myself any reusability or simplification. Now I just have a
very specific window with a set of very specific components. It
does not really make sense to have an IConfigVO, as I can't think
of other places in the app such configs would be needed, which
makes this data request event also very specific and non reusable.
This is where I thought the read only model may be applicable, so
in the top level window/mediator we would inject an IReadTournament
and use it's values for things like useDivision, isCollege,
isHighSchool (maybe there are different rulesets for college and
high school?) directly instead of creating another intermediary
with a config VO. Whenever I start to do something like this I get
that "code smell" I guess because it seems to me I am mixing view
logic with application data, and the separation of roles is not
very clean.</p>
<p>Finally, another idea has just crossed my mind, does it make any
sense to have "static" models? i.e. they hold data that is used
commonly across the app, but this data is never (or very rarely)
updated by anything else. I'm thinking this because I definitely
have a collection of static data that gets displayed in various
components several places in the app (ButtonBar, DataGrid, ...
etc), so I could hold this list in a model and pass it to specific
component implementations, just like in the DropDown example.</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-07T09:15:47Z2015-07-07T09:15:47ZInject model(s) into specific purpose view<div><p>First an erratum to my previous post.<br>
If you want to inject IAddUser somewhere and IReadUser somewhere
else, this mapping is incorrect:</p>
<pre>
<code>injector.map(IReadUser).toSingleton(UsersModel);
injector.map(IAddUser).toSingleton(UsersModel);</code>
</pre>
<p>I meant to show you how you can map just one of the interfaces
and didn't notice the confusion.</p>
<p>This is correct:</p>
<pre>
<code>var usersModel:UsersModel = injector.getOrCreateNewInstance(UsersModel);
injector.map(IAddUser).toValue(usersModel);
injector.map(IReadUser).toValue(usersModel);</code>
</pre>
<p>Now, you can inject IAddUser into a class where you, guess what,
add users to the list, and IReadUser into the class that just needs
the list of users.</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-07T15:48:32Z2015-07-07T15:48:32ZInject model(s) into specific purpose view<div><blockquote>
<p>This is where I thought the read only model may be applicable,
so in the top level window/mediator we would inject an
IReadTournament and use it's values for things like useDivision,
isCollege, isHighSchool (maybe there are different rulesets for
college and high school?) directly instead of creating another
intermediary with a config VO.</p>
</blockquote>
<p>This sounds good, but it is still not clear to me whether
TournamentModel is having all these properties, useDivision,
isCollege, isHighSchool, or you would inject several models into
the view to get all the needed settings?</p>
<p>Let's just think about what that window really needs to
know.<br>
I'll use an analogy with a Flex component. When you create a new
Button, you set its properties like visibility, enabled, color,
label text, etc. The Button doesn't need to know whether the parent
component is a Group or a BorderContainer or in which state the
parent component is in. You don't add code to your Button which
will check if parent.isBig then set label="Big Button" or something
like that. The parent of the Button is the one deciding how the
Button will look like, and the Button doesn't care about its
parent, it just exposes APIs for its properties.</p>
<p>Likewise, the view containing a divisions list doesn't need to
know if tournament.useDivisions is true or false, it just needs to
know if the divisions list is to be shown or not (or to be added to
the stage or not). Ideally, the view should only expose a
divisionsVisibility property and it shouldn't care how or who will
set it. Maybe later you will want to make the visibility of the
list dependent on other conditions as well, so what will you do?
Will you inject yet another model and ignore the tournament
model?</p>
<p>When dealing with settings for a view coming from many models,
my preference would be to <em>not</em> make the view directly
dependent on all of them. Even if that specific view is not
reusable (yet) and even if it is more work, I would create a class
like the mentioned SomeViewBehaviour, with all the properties
needed by the specific view/window.<br>
The view would be injected with IGetViewBehaviour. I would create,
set its data and open the window in a command. Before opening it,
the command would assemble the data for SomeViewBehaviour from
several models (IReadTournement, IReadSomeOtherModel...).
SomeViewBehaviour would be injected into the command as
ISetViewBehaviour:</p>
<p>viewBehaviour.divisionsVisibility = tournament.useDivisions;<br>
viewBehaviour.someOtherProperty =
someOtherModel.someOtherProperty;</p>
<p>If you later decide that the view's behaviour should be dictated
by other conditions or combinations of models, you just have a
single command where you make the changes. The dependencies are
reduced: One View <---> One Behaviour Class as opposed to One
View <--->Model 1, Model 2, Model 7, Model 11.</p>
<p>(I'm not talking here about the data providers for the dropdowns
which were actually mediated sub-views in my mediated lists example
and were getting there data independently of the parent view. )</p>
<p>You could also have 2 mediators for a view/window, if the view
would implement 2 interfaces. One mediator would just take care of
the loading of view's settings and the other of collecting view's
data and sending it to whomever needs it. This is just a thought, I
don't know if it is useful for you or not.</p>
<blockquote>
<p>Finally, another idea has just crossed my mind, does it make any
sense to have "static" models? i.e. they hold data that is used
commonly across the app, but this data is never (or very rarely)
updated by anything else.</p>
</blockquote>
<p>So, now we are back to a global model? ;) I don't know how to
say it without repeating myself. Theoretically, if it contains just
"static" settings, then there is no harm in injecting it where ever
you need it, as a read only interface. Is your TournamentModel
holding such settings? If the answer is yes, then you don't need a
special or a specific ViewBehaviour class for your views.<br>
I'm sure you're aware of the associated risks with having such a
model 'used commonly across the app', like its tendency to become
an "everything drawer" and you'll be carefully designing it. I
wouldn't call it a model, though. Models can "do" things, like
changing the state of data... This 'holding application's settings'
class, however you name it, could implement several read only
interfaces: IReadTournament, IReadEducation, IReadSomeRules and so
on, so a view needing only tournament settings would be injected
with only the IReadTournament and not the IReadTheEntireClass.</p>
<p>Conclusion: injecting configuration data into views as read-only
interfaces is acceptable.<br>
I hope this helps you at least a little bit.<br>
There might be other solutions as well, but unlike you, I can't see
your entire project and requirements to give you a more practical
and concrete answer, and besides, I also don't hold all the answers
:)</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-07T21:14:18Z2015-08-19T21:05:55ZInject model(s) into specific purpose view<div><p>Ok, this seems great, once I wrote everything out it got very
clean. I am just missing how exactly to inject the behavior created
in the command as ISetViewBehavior into the view as
IGetViewBehavior. Is it just
<code>injector.injectInto(view)</code>?</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-07T21:31:57Z2015-07-07T21:31:57ZInject model(s) into specific purpose view<div><p>Short answer: look for viewProcessorMap</p>
<p>viewProcessorMap.map(SomeView).toInjection();</p>
<p>More tomorrow, if need be..</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T13:53:32Z2015-08-19T21:05:55ZInject model(s) into specific purpose view<div><p>Ok, I think I have everything wired up properly. I was even able
to abstract the view behavior to a top level
NewRecordWindowBehavior class that holds behavior common to all
windows adding a record to the database. So we have the
following</p>
<p>1) NewRecordWindowBehavior, IGetNewRecordWindowBehavior,
ISetNewRecordWindowBehavior. The class implements both interfaces,
IGet has only getters, ISet has only setters.</p>
<p>2) NewPlayerWindowBehavior, IGetNewPlayerWindowBehavior,
ISetNewPlayerWindowBehavior similar to above.</p>
<p>3) The injector maps ISetNewPlayerWindowBehavior,
IGetNewPlayerWindowBehavior to type NewPlayerWindowBehavior.</p>
<p>ViewProcessorMap injects behavior correctly into view. All is
well.</p>
<p>My one complaint: Now, if we want to change the behavior of one
view, we have 3 separate classes we have to update. Is this the
best we can do?</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T14:49:04Z2015-07-08T14:49:04ZInject model(s) into specific purpose view<div><blockquote>
<p>My one complaint: Now, if we want to change the behavior of one
view, we have 3 separate classes we have to update. Is this the
best we can do?</p>
</blockquote>
<p>Which 3 classes?</p>
<p>I'm sorry, but I don't know what you mean.<br>
I don't understand the relationship between NewRecordWindowBehavior
and NewPlayerWindowBehavior.<br>
You said that a window extends a NewRecordWindowBehavior.<br>
Is a new window extending NewRecordWindowBehavior and implementing
a NewPlayerWindowBehavior, so it has the functionality common to
all windows plus the one specific for a player window?</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T14:50:47Z2015-07-08T14:50:47ZInject model(s) into specific purpose view<div><p>I meant to say :<br>
Is a new window extending NewRecordWindow which implements the
IGetNewRecordWindowBehavior, ISetNewRecordWindowBehavior.</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T15:07:47Z2015-08-19T21:05:56ZInject model(s) into specific purpose view<div><p>Sorry to come full circle, but I think now I've found the best
solution...</p>
<p>As I was working with more views and planning out more
ViewBehaviors, I came to realize that the settings that determine
behavior (e.g. useDivisions) are used in many more places, and in
views that are not dynamically created as well. The roadblock for
me was for dynamically created views -- mediators that do not exist
yet won't receive framework events. Enter RelaxedEventMap. I had
read about this extension but not fully understood what it was for.
It is now clear to me what I want is to essentially "broadcast" a
setting made in the model to all interested view components, and
mapping relaxed events will broadcast to existing and yet to be
created mediators (if I understand correctly).</p>
<p>To clear up my last post, here is a diagram of inheritances</p>
<p>NewPlayerWindowBehavior <--extends --
NewRecordWindowBehavior</p>
<p>IGetNewPlayerWindowBehavior <--extends--
IGetNewRecordWindowBehavior</p>
<p>ISetNewPlayerWindowBehavior <--extends--
ISetNewRecordWindowBehavior</p>
<p>NewRecordWindow is pretty much an abstract class, theres not
actually an implementation of it, but each window that adds a new
record will get behavior that extends the behavior of an abstract
NewRecordWindow -- that was the idea at least.</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T15:14:47Z2015-07-08T15:14:47ZInject model(s) into specific purpose view<div><p>So, the problem about how to update the 3 classes is solved and
now your question is about the relaxed event map?</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T15:23:14Z2015-08-19T21:05:56ZInject model(s) into specific purpose view<div><p>I'm going to try to implement the relaxed event map, it seems
pretty straightforward so no questions there.</p>
<p>In the case that I do use a ViewBehavior, I'm asking if</p>
<p>a) I implemented your suggestion of ISetViewBehavior,
IGetViewBehavior, ViewBehavior correctly? (don't worry about the
inheritance I mentioned above)</p>
<p>b) When we add or remove a "behavior/setting" from the
ViewBehavior class, we have to change all 3 classes, the two
interfaces, and the implementation, right? Is that the best that we
can do if we want to use the ViewBehavior approach?</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T15:48:19Z2015-07-08T15:48:19ZInject model(s) into specific purpose view<div><p>To a) yes, it seems so</p>
<p>To b) if you mean adding or removing methods to/from the
ViewBehaviour class, then yes, you have to change both interfaces
as well or rather vice versa, ViewBehaviour would have to implement
the methods declared in the interface class(es). That's the nature
of interfaces. Once you are done with designing your classes and
your project will be more 'stable', you probably won't have to
change these classes anymore or at least not very often.<br>
Is that what you meant?</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-07-08T17:15:04Z2015-08-19T21:05:56ZInject model(s) into specific purpose view<div><p>Yes</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-09-24T15:57:18Z2015-09-24T15:57:18ZInject model(s) into specific purpose view<div><p>Up until now I have been using your style of mediated lists with
no problem. However I encountered a relatively glaring performance
issue and was wondering if there was any way to improve it.</p>
<p>A model contains 3 array collections that need to be passed to a
view to populate 3 corresponding datagrids. These data are all
related and it makes sense for them to reside in the model as
separate collections.</p>
<p>To view/edit this data, the user opens a popup spark window
containing a view of these 3 datagrids. This view has a mediator
that listens for LIST_DATA_CHANGED and the appropriate view_id, and
dispatches a LIST_DATA_REQUESTED. The problem: it takes, on
average, 700ms for the data to complete its trip. The window opens,
and the datagrids sit blank for almost a second before appearing
with data... which really isn't acceptable.</p>
<p>I've tried a few workarounds:<br>
-injecting the ListDataProviderModel directly into the mediator
-injecting the DataModel directly into the mediator -using the
RelaxedEventMap and dispatching the request event from the window's
mediator</p>
<p>Nothing has really drastically improved the performance. Do you
have any suggestions for optimizing this procedure?</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-09-25T12:11:27Z2015-09-25T12:11:27ZInject model(s) into specific purpose view<div><p>Hi,</p>
<p>I think that the behaviour you're describing has rather to do
with the way Flex is rendering a DataGrid than with robotlegs.</p>
<p>There are few known performance issues with a Flex DataGrid. You
might want to look into these.</p>
<p>How fast a datagrid shows its content depends on many factors.
For example:</p>
<ul>
<li>
<p>on the size of the dataprovider</p>
</li>
<li>
<p>on the number of shown rows</p>
</li>
<li>
<p>on item renderers and maybe the display objects they use</p>
</li>
<li>
<p>on sorting or filtering functions applied to the dataprovider as
a collection</p>
</li>
<li>
<p>on layout settings, like dynamic vs. fixed row height or
width</p>
</li>
<li>
<p>on effects applied to the datagrid or its subcomponents
(transition, animation) , resizing</p>
</li>
</ul>
<p>I suggest running a few tests.<br>
Start with a simple application where you just open a simple
datagrid in a simple window (simple == no special layout, no
effects, no filtering or sorting of the dataprovider
collection..).<br>
Use a mock data provider with a low number of items.<br>
Start with a low number of visible datagrid rows.<br>
Increase the size of the collection used as data provider.<br>
Increase the number of shown rows.<br>
Add layout constraints as used in your real app.<br>
Add array/arraycollection filters, sorting, if needed.<br>
If you're using item renderers, add them too.<br>
Try the same with having 2 or more datagrids in your window.</p>
<p>If everything works as expected, add robotlegs and only the
classes needed for testing .<br>
Again, start simple and increase the complexity gradually.<br>
Also, when using robotlegs, open a window without datagrid(s)
and<br>
check the time elapsed from the opening of the window until
receiving a dataprovider from model.<br>
Then add a datagrid and see the time it needs to render and to
dispatch addedToStage and creationComplete and to become
visible.</p>
<p>You can use my example on github (<a href="https://github.com/Ondina/robotlegs-bender-mediated-lists">https://github.com/Ondina/robotlegs-bender-mediated-lists</a>)
to add your use case.<br>
If you are sure that the behaviour you're seeing is not due to Flex
and you think that robotlegs is the culprit for the strange
behaviour of your datagrids, you should attach the modified app
containing your tests so I can take a look at it.<br>
In any case let me know about your findings.</p>
<p>As I mentioned in one of our discussions, I think that
"paginating" large amounts of data is a good idea.</p>
<p>When delays in loading of large data providers are not
avoidable, I use to set the component's visibility to false until
it gets its data and to show a 'loading...' icon or text for the
time being.<br>
Same can be achieved with view's states, but they can be tricky
sometime..</p>
<p>I don't know how much you know about Flex components' life
cycle. Here are a few links on the topic (that I've already posted
elsewhere):<br>
<a href="http://help.adobe.com/en_US/flex/using/WS460ee381960520ad-2811830c1">
http://help.adobe.com/en_US/flex/using/WS460ee381960520ad-2811830c1</a>...<br>
<a href="http://www.developmentarc.com/site/wp-content/uploads/pdfs/understa">
http://www.developmentarc.com/site/wp-content/uploads/pdfs/understa</a>...<br>
<a href="http://www.dlgsoftware.com/primers/Primer_on_Flex3_Component_Lifecy">
http://www.dlgsoftware.com/primers/Primer_on_Flex3_Component_Lifecy</a>...<br>
<a href="http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c">
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c</a>...<br>
From the above article:<br>
"creationComplete Dispatched when the component, and all its child
components, and all their children, and so on, have been created,
laid out, and are visible. Flex dispatches the creationComplete
event for a container when those children that are initially
required are fully processed and drawn on the screen, including all
required children of the children, and so on. Create a listener for
the creationCompleteevent, for example, if you must have the
children’s dimensions and positions in your event handler. Do
not use the creationComplete event for actions that set layout
properties, as doing so results in excess processing time."<br>
I hope this helps.<br>
Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-09-26T00:13:17Z2015-09-26T00:13:17ZInject model(s) into specific purpose view<div><p>OK, I've done some further investigating. I think you are right
about it being Flex based. Here are some more details and concrete
numbers.</p>
<p>First: All three DataGrids are relatively small and their length
is fixed (11, 9, and 12 rows). They are fixed height and fixed
width. Each row has 4 columns, 3 of which are ItemRenderers. One is
a custom CheckBox ItemRenderer. The other two are inline
NumericStepper ItemRenderers. Grid code:</p>
<pre>
<code><s:DataGrid dataProvider="{dakFieldCols}" width="250" height="337" selectionMode="none">
<s:columns>
<s:ArrayList>
<columns:CheckBoxColumn dataField="selected" headerText="" />
<s:GridColumn dataField="display" width="80" headerText="Field"/>
<s:GridColumn dataField="width" width="55" headerText="Length" rendererIsEditable="true">
<s:itemRenderer>
<fx:Component>
<s:GridItemRenderer>
<s:NumericStepper value="@{data.width}" minimum="1" maximum="99" width="40"/>
</s:GridItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:GridColumn>
<s:GridColumn dataField="order" width="40" headerText="Order" rendererIsEditable="true">
<s:itemRenderer>
<fx:Component>
<s:GridItemRenderer>
<s:NumericStepper value="@{data.order}" minimum="1" maximum="99" width="40"/>
</s:GridItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:GridColumn>
</s:ArrayList>
</s:columns>
</s:DataGrid></code>
</pre>
<p>Second: I use a generic OpenPopupWindow Signal to open the
window. The Signal has the Window Class as it's argument and is
mapped to a command which takes the class from the signal and opens
with window after passing it to the viewManager.</p>
<p>The window is structured as follows:</p>
<pre>
<code>-SetupWindow
|-VGroup
|-HGroup
|-VGroup
|-SetupView1
|-SetupView2
|-VGroup
|-DataGridsView
|-DataGrid1
|-DataGrid2
|-DataGrid3
|-DataMonitorView</code>
</pre>
<p>Here are some numbers:</p>
<p>-Using the RelaxedEventMap and dispatching the
ListDataProviderEvent.LIST_DATA_REQUESTED from the
SetupWindowMediators initialize function():</p>
<pre>
<code>[trace] OPEN POPUP WINDOW SIGNAL DISPATCHING 9889
[trace] 9891 DEBUG Context-0-72 [object ViewManagerBasedExistenceWatcher] Adding context existence event listener to container SetupWindow2091
[trace] POPUP WINDOW OPENED AND VISIBLE 10647
[trace] dispatching dataprovider event: 10964
[trace] receiving dataprovider event: 10966
[trace] done setting dataproviders: 10967</code>
</pre>
<p>Listening to the Context from the DataGridsViewMediator and
dispatching the ListDataProviderEvent.LIST_DATA_REQUESTED from the
DataGridsViewMediator's initialize function:</p>
<pre>
<code>[trace] OPEN POPUP WINDOW SIGNAL DISPATCHING 26663
[trace] 26666 DEBUG Context-0-8e [object ViewManagerBasedExistenceWatcher] Adding context existence event listener to container SetupWindow3540
[trace] POPUP WINDOW OPENED AND VISIBLE 27189
[trace] dispatching dataprovider event: 27436
[trace] receiving dataprovider event: 27437
[trace] done setting dataproviders: 27437</code>
</pre>
<p>In both of these cases, the datagrids sit blank while after the
last line is traced and then appear with the data. My conclusion is
that the ItemRenderers are very slow. Without them and just
displaying the data, everything happens quite fast.</p>
<p>If you have any suggestions for improving performance I would be
very grateful! But as it seems this is no longer a RobotLegs issue,
don't feel obligated. I have scoured the Adobe docs for information
on itemRenderer performance but not been able to find very
much!</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-09-26T15:17:07Z2015-09-26T15:17:07ZInject model(s) into specific purpose view<div><blockquote>
<p>All three DataGrids are relatively small and their length is
fixed (11, 9, and 12 rows). They are fixed height and fixed
width.</p>
</blockquote>
<p>That's good, because a fixed height and width are making the
rendering faster. Also try to set the rowHeight to a fixed
value.</p>
<blockquote>
<p>All three DataGrids are relatively small and their length is
fixed (11, 9, and 12 rows).</p>
</blockquote>
<p>You mean the number of visible rows or the length of their
dataproviders?</p>
<blockquote>
<p>My conclusion is that the ItemRenderers are very slow. Without
them and just displaying the data, everything happens quite
fast.</p>
</blockquote>
<p>Except for the CheckBoxColumn that I can't see, the other
columns look ok and I think that the datagrid is quite decent, not
too big, not too many renderers and so on. But, maybe having 64+
NumericSteppers in the 3 datagrids is making Flex dizzy?;) You
could build your own NumericSteppers inside of a custom renderer, a
label for the value, one for the + sign and one for the - sign, and
of course the corresponding handlers. Labels are lightweight and
get rendered faster than a Numeric stepper.</p>
<p>I'm not sure, but I think that the 2-way-binding in your item
renderers plays a role in the delayed rendering. You may want to
investigate this further.<br>
Anyway, I would use a custom renderer where I could override the
set data() or listen for dataChange event, instead of using
bindings, if possible. See the linked articles further down.</p>
<p>Are your datagrids embeded as mxml components inside of your
SetupWindow?<br>
Again, not sure if this helps at all, but try to add them through
actionscript from within SetupWindowMediator's initialize(), by
calling a SetupWindow's API and see if it's any better.</p>
<p>I don't feel obliged to answer questions that are not related to
robotlegs:) When I can, I answer such questions, also because I'm
also interested in topics like flex datagrid, item renderers,
etc....<br>
But I'm afraid I can't help you this time.<br>
First, because I am no expert in itemRenderers. Second, I'll be on
holiday for a while, starting tomorrow, so that I can't experiment
myself with a use case like yours.</p>
<p>Stackoverflow is a good place for asking flex related questions.
If you're are lucky, you get an answer from one of the many Flex
experts there.</p>
<p>Articles on item renderers:<br>
<a href="http://www.adobe.com/devnet/flex/articles/itemrenderers_pt1.html">http://www.adobe.com/devnet/flex/articles/itemrenderers_pt1.html</a><br>
<a href="http://www.adobe.com/devnet/flex/articles/itemrenderers_pt2.html">http://www.adobe.com/devnet/flex/articles/itemrenderers_pt2.html</a></p>
<p><a href="http://www.adobe.com/devnet/flex/articles/flex-mobile-performance-checklist.html">
http://www.adobe.com/devnet/flex/articles/flex-mobile-performance-c...</a></p>
<p>Good luck.<br>
If you find a solution, please post about it.</p>
<p>See you.</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-10-22T14:00:01Z2015-10-22T14:00:01ZInject model(s) into specific purpose view<div><p>I hope your vacation went well. I wanted to let you know that
creating custom Numeric Steppers like you said greatly improved the
speed of opening the window!</p></div>dkartentag:robotlegs.tenderapp.com,2009-10-18:Comment/372733072015-10-22T14:45:25Z2015-10-22T14:45:25ZInject model(s) into specific purpose view<div><p>Yes, the vacation was great but too short, thanks for asking. I
could use another one already...</p>
<p>That's good news about the improved performance of your
datagrid! Thank you for letting me know about it. I really
appreciate the feedback :)</p></div>Ondina D.F.