This is what I'm concluding in MobileTrader:
MobileTrader has "sub-views" for WatchList and Alerts. Each of these
sub-views has its own controller (WatchListController,
AlertViewController) which are responsible for taking events from the view
and updating the model.
The first task is to get the controller to know about the model. We are
talking about the model holding the data, not the FlexJS "model" which
most components have that hold values for the component's properties. So
I'm calling this the "dataModel". The circular dependencies are arising
because the controllers are directly references their views and grabbing
data out of the view.
I removed the attachment of the controller to the sub-view from the CSS.
In the view (eg, WatchListView), I explicitly name the controller bead and
use data binding to pass in the model the controller needs to use.
<js:beads>
<js:ViewDataBinding>
<controller:WatchListController dataModel="{dataModel}" />
</js:beads>
(Note: The WatchListView's dataModel is set using data binding from the
outer MyInitialView).
Then I removed all references to WatchListView from WatchListController.
This caused several errors because WatchListController was referencing the
view to get to the data on the screen which needed. For example, it needed
the symbol to watch:
view.symbolName.text
Since WatchListController now knows nothing about the view, I created
custom events for the WatchListView to dispatch that contained the data
the controller needs. So when the Set button is picked, the button's event
handler in WatchListView now does:
var event: new AddSymbolEvent(symbolName.text);
dispatchEvent(event);
The WatchListController is looking for this event and can use the symbol
value from the event without referring to the view at all.
I applied this technique to the AlertsView and AlertsViewController. All
in all, the code got cleaner and more readable. The view takes care of
updating the view UI components and the controller takes care of updating
the model.
The pattern now works something like this:
1. Give the sub-view controller bead bindable get/set methods for the
dataModel it needs. Don't forget to add the ViewDataBinding bead to the
sub-view class.
2. Create custom events to pass data from the sub-view controls over to
the controller.
3. Have the controller set up event listeners for these custom events in
its strand-setter; the "strand" is really the sub-view.
4. When the view receives some user interaction, have it create a custom
event with the data and dispatch it.
5. The controller will receive the custom event and modify the model.
6. The view can update the UI controls (eg, textField.text = "") after
sending the event.
For simpler projects, like the TodoListSample or DataBindingExample, the
controller can implement IDocument and, when the "document" (aka,
Application) is set, it can get the reference to the application data
model and set up listeners for it.
I will be checking these changes in shortly today or tomorrow (USA, EDT)
morning.
‹peter
On 8/16/16, 8:33 PM, "Alex Harui" <[email protected]> wrote:
>
>
>On 8/16/16, 2:20 PM, "Peter Ent" <[email protected]> wrote:
>
>>
>>Hi,
>>
>>I wanted to post what I've done before I commit the code to get an idea
>>if
>>this is the right approach.
>>
>>Background: a circular dependency is when class A references class B
>>which
>>references class B. Pretty simple.
>>
>>In many of the FlexJS examples, there are circular dependencies between
>>the application class and the application's controller. For example,
>>DataBindingExampleApp references its controller, MyController, which has
>>a
>>reference back to the application. Likewise, the TodoListSampleApp
>>references its controller which holds a reference to the app class. The
>>objective in both examples is provide the controller with a reference to
>>the model.
>>
>>In both of these cases, my solution is to remove the explicit reference
>>to
>>the application (eg, DataBindingExample) in the controller and replace it
>>with the Application class and then extract what it needs into local
>>variables.
>
>The above sounds like a good plan.
>
>>However, MobileTrader is bit trickier. MobileTrader has several mobile
>>"views" and each has its own controller. The circular dependency in this
>>case is between these secondary views and their respective controllers.
>>The way I approached this was to make a new interface in the MobileTrader
>>example src, called "IBeadControllerWithModel" which extends
>>IBeadController and adds a getter/setter for a model. Now the view can
>>simple reference its controller using this new interface and set the
>>model
>>so the controller can now modify it.
>
>I don't know this code very well, but I poked around a bit and it appears
>the view knows about the controller only because it is assigning the model
>to the controller. IMO, the controller should pick up the model from the
>strand. If it is a timing issue where the model isn't set when the
>controller is put on the strand, the controller should be able to look for
>a modelChange event or maybe even initComplete.
>
>Thoughts?
>-Alex
>