Peter, I like the idea of declaring the controller as a bead in the view.
But shouldn't the controller be able to know about (have references to) the View as long as the View doesn't know about the controller (which it shouldn't, IMO). The view should dispatch events (for example, converting a "click" on a checkbox to "LicenseAcceptanceCheckboxSelectionChange" but it should be ok for the controller to have a reference to the view to access data from the widgets, validate them, and then apply them to the model. Passing data via events means copying data and references and the controller code might need other values from other widgets in the view. It also means fewer custom event classes. IMO: Models should not reference views or controllers Views should reference models but not controllers Controllers should reference models and views. I think there aren't circularities in that set. Thoughts? -Alex On 8/17/16, 1:46 PM, "Peter Ent" <[email protected]> wrote: >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 >> >
