Mediator to pass data to sub views

alebianco

06 Aug, 2015 08:06 PM

hi all,
I'm looking for a suggestion or a best practice about an architectural issue I've been struggling with lately.

I've a Model that contains an array of data.
This information has to be viewed as a list with a fixed number of elements, so I've a ContainerView and n ItemView that display each item. Both ContainerView and ItemView are mediated.

Ideally I'd like ItemMediator to set the relevant data into it's own view but that requires one of them to know their "position" to pick the rough stuff from the model, which I'm not too happy about.
Maybe the ContainerMediator should be responsible to set the data to his children and ItemMediator handles just the following user interactions? This kind of makes sense but requires a view to expose (or set data to) his children views. Also, this would probably be my favourite choice for a non-fixed size list of items.

I know there's no "right" solution that fits every situation, i'm more interested in the best practices and how other people solved similar problems.

Thanks all!

PS: a little background. I'm not using RL2 nor actionscript, but since it's my favourite framework, I've ported the key bits of it to Haxe while using a swiftsuspenders-like library as foundation for it. Basically it's pretty close to the real deal, probably with some extra but still for the added fun...

where view is the ContainerView injected into ContainerMediator.
This wouldn't be very nice.

This kind of makes sense but requires a view to expose (or set
data to) his children views

This sounds like you certainly meant to set subviews' data
inside of containerView, right?
In my opinion, that could be just fine.

Some very general rules for parent-child communication on a
component level, when components aren't mediated:

parent accesses child's API

child dispatches events for the parent to hear

Top to bottom through API, bottom to top through events.

Now, in the world of mediated views, we want views to be as
encapsulated as possible and that's why we try to let views
communicate with each other via their mediators. And that's why it
bothers you to access child-views directly from the parent-view,
right?

Ideally I'd like ItemMediator to set the relevant data into it's
own view but that requires one of them to know their "position" to
pick the rough stuff from the model, which I'm not too happy
about.

Why is itemView's data depending on view's position? Could you
provide more details on this?
Does ContainerView know about children's position? Are the children
added dynamically?
If they are added dynamically, can't you assign an ID for each
added view?
In the case of accessing ItemView's API, how is ContainerView
deciding which data is meant for a certain ItemView? Is the
position of one subview always the same?

From what you said, I infer that the model keeps a map of view's
data and their positions or maybe IDs. Is that so?
Is ContainerMediator making a request for subviews' data or is
ContainerMediator just listening for models events?
Could a map of children's ids to their position - created when the
subviews are added to the parent view - be of any use to you?
ContainerMediator would send the map as a payload of the event that
is requesting data from the model.
Could each ItemMediator decide which data is meant for its view, if
the model would dispatch events with an additional info about
ids?

Are the ItemViews similar from a layout point of view, having
just different content? Or is their content and layout completely
different and ContainerView is just presenting them as a kind of
list. Or, is an ItemView more like an item renderer?

If having each ItemMediator get the data for its own view turns
out to be too complicated or convoluted, I'd opt for letting
ContainerView provide subview's data.
What about a view factory used inside of ContainerView that would
encapsulate the logic of setting subviews' data?

Hopefully others will have more suggestions for you, too, after
you provide a bit more details.

Hi Ondina,
loads of good ideas here already, as always. Let see if I can give some extra details ...

At a very high level, ContainerView acts as a list and you can consider ItemView as the renderer for the data of such list.
The data is being loaded through a Service in a Command, triggered by a Signal triggered somewhere else. So both Container and Item only receive a notification of the data being changed. The data changes in blocks, a new Array of length N replaces the previous set of values.
I have two separate cases, one where the N length is fixed and the other is dynamic. I could use the same generic ContainerView or make two specialised classes to optimise performances but I'd like to follow the same set of patterns for both cases. In both cases the items of the list are displayed in a very similar way.

I think it would be reasonable to have the ContainerMediator to create the ItemViews and assign them an index, so that the ItemMediator could use it when the Model changes. This way everything related to the ItemView management would be contained in it's Mediator.

One possible issue is that, in the fixed-N component, the ItemViews are created by a "third party" (a processor that parses a json file and creates the appropriate view classes) so the ContainerMediator would have to go through the childs after their creation and assign ids. An approach that could open the door to various issues potentially.

We also thought to keep a map ID->ItemView in the ContainerMediator and generated after the views auto-creation. So that ContainerMediator would have to deal with setting the data while ItemMediator would deal only with user interactions. I don't dislike this but it didn't find the team's consensus.

Thank you for providing more info:)
I'm afraid that I won't be able to give you a concrete
solution/suggestion, because the use case is still too abstract.
But, I realize that you can't disclose much about your project.

At a very high level, ContainerView acts as a list and you can
consider ItemView as the renderer for the data of such list.

If it is a list, why don't you implement the concept of a
dataProvider in the ContainerView and the set data() in the
ItemView? Even if it's not a regular list, you can implement a
reduced functionality of a data provider in your ContainerView.
Your ContainerView is the owner of those ItemViews, so it should be
allowed to set their data.

The data is being loaded through a Service in a Command,
triggered by a Signal triggered somewhere else.

I've a Model that contains an array of data. This information
has to be viewed as a list with a fixed number of elements, so I've
a ContainerView and n ItemView that display each item. Both
ContainerView and ItemView are mediated.

When you create the array/collection from the loaded data, you
could also assign an id for each item. When an ItemView receives
its data, it also receives an id, that it can use for further
requests.

One possible issue is that, in the fixed-N component, the
ItemViews are created by a "third party" (a processor that parses a
json file and creates the appropriate view classes) so the
ContainerMediator would have to go through the childs after their
creation and assign ids.

I don't understand why a fixed length of ItemViews is a problem.
There must be a reason for that, but I can't see it, and the
additional info you provided doesn't make it more clear (at least
not to me). Maybe you meant that an ItemView at a certain position
in the list should always receive the same type of data? Like
ItemView at position 0 gets a userImage, ItemView at position 1
gets user's name, age..., ItemView at position 2 gets a list of
books that the user likes, etc ?

The processor you are talking about would be something like a
factory, in my understanding. If it creates the ItemViews classes
dynamically, why can't it also pass views' data in the same
process. Or at least create a map of indexes to ids to be stored in
a model?

We also thought to keep a map ID->ItemView in the
ContainerMediator and generated after the views auto-creation.

I wouldn't keep the map inside the Mediator or the View, but in
a Model, probably in the same Model that is containing the
collection of items' data. (I also wouldn't create or add subviews
directly in the Mediator. That is View's responsibility.)

In my mind you need a way to 'identify' the children, either by
index or by an id of some sort.

The map / dictionary of indexes to ids (or other criteria) can
be created

1 either by the Model or the factory (your 'processor') that
creates the subviews ( Model->dictionary->View)
2 or by the views themselves (View-> dictionary ->Model)

For example, when ContainerView adds an ItemView, it also adds
the child's index->id to a dictionary, and when it is done
adding its children it dispatches an event/signal with the
dictionary of registered children as a payload, so that a model can
store that dictionary and use it to filter the view's data as
needed.

The data changes in blocks, a new Array of length N replaces the
previous set of values.

This would mean that if ContainerView were a regular List, when
model's data changes, the list would simply refresh its
dataProvider, and you wouldn't need to let each item request its
data. It is again not clear to me why you need each ItemView to be
able to request its own data when you deal with a fixed list
length, but I'm sure there is a good reason for this.

It also remains unclear if the criteria used for distributing
the loaded data to the ItemViews are external to the application
(an external id or name or something else), or are defined in the
Model or in the ContainerView. I also still don't understand if the
data presented by each ItemView has the same structure or not.

I think this is important to know, because if for example the
loaded data contains something like a userImageURL,
userPersonalData, userPreferences, then it might be easy to create
an ItemView that exhibits the behaviour of showing images (by
implementing a IShowImages interface), another that implements an
IPersonalData, etc. Their Mediators could add listeners to
events/signals specific for view's role... This is pure speculation
and it probably has little or no value for your concrete use
case.

I have two separate cases, one where the N length is fixed and
the other is dynamic.

So, the dynamic one works and you have trouble implementing the
same logic to the fixed length one?
Why can't you create a dynamic list with a fixed length?

So that ContainerMediator would have to deal with setting the
data while ItemMediator would deal only with user interactions. I
don't dislike this but it didn't find the team's consensus.

The ContainerView, not the ContainerMediator, would set its
children's data. The ContainerMediator would just pass the data
from the model to the ContainerView.
What's your colleagues' argument against this?