Seems really weird to be put a dataModel property on an object whose sole purpose is be a grouping mechanism. I understand wanting to preserve the model/view/controller paradigm, but wouldn't it more efficient to give the data model to the things that actually need the data model in as direct a fashion as possible? The data is readily available in this class that has this structure and passing it to the widgets individually via data binding would make things a lot easier than having to have these components discover the data in their life cycles.
I have to really look over how I created the whole mobile component classes and make sure they conform to this pattern because I think it will be some re-writing. Maybe not too much, but I have to go and wrap my head around it. —peter On 8/17/16, 7:10 PM, "Alex Harui" <[email protected]> wrote: >OK, I think I get it now. The key thing is that the "View" isn't really a >view like a ButtonView or CheckBoxView is to Button or Checkbox. Instead, >a View is a top-level component. > >Application is a top-level component. It has a "model", "controller", and >"initialView" property. You were able to eliminate circularities by >having the 3 rules below because the controller is referencing the >"initialView" and "model" and not the Application (as it should). > >The equivalent for StackedViewManager may require terms borrowed from the >Flex SDK: "navigator" and "navigatorContent". If StackedViewManager is >actually a StackNavigator and there was a NavigatorContent tag with view >and controller, that would be more similar to the Application pattern: > ><StackedNavigator> > <NavigatorContent title="Watch List" dataModel="{applicationModel}"> > <view> > <View> > UI Widgets > </View> > </view> > <controller> > <WatchListController /> > </controller> > </NavigatorContent> ></StackedNavigator> > >And I think that would also eliminate circularities because the controller >would be referencing the View and not the NavigatorContent. > >Thoughts? >-Alex > >On 8/17/16, 2:29 PM, "Peter Ent" <[email protected]> wrote: > >> >> >>On 8/17/16, 5:09 PM, "Alex Harui" <[email protected]> wrote: >> >>>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). >>As soon as I added the controller has a bead, the circular dependency was >>formed. I had started with the previous changes where I had removed the >>circular dependency - the controller was just referenced in the CSS. >>> >>>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. >> >>I thought using custom events was a nice way to separate the concerns. >>What do other people think - do you use a lot of custom events in your >>application code or do you get some simple event and then go grab the >>data >>out of the controls? >> >>> >>>IMO: >>>Models should not reference views or controllers >>>Views should reference models but not controllers >>>Controllers should reference models and views. >> >>I don't see how you can remove the dependency when the View MXML explicit >>references the Controller MXML in the <js:beads> list. Perhaps we have >>something wrong in the fundamentals then. >> >>> >>>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 >>>>> >>>> >>> >> >
