flex-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Alex Harui <aha...@adobe.com>
Subject Re: FlexJS: Circular Dependency
Date Wed, 17 Aug 2016 23:10:13 GMT
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" <pent@adobe.com> wrote:

>
>
>On 8/17/16, 5:09 PM, "Alex Harui" <aharui@adobe.com> 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" <pent@adobe.com> 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" <aharui@adobe.com> wrote:
>>>
>>>>
>>>>
>>>>On 8/16/16, 2:20 PM, "Peter Ent" <pent@adobe.com> 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
>>>>
>>>
>>
>

Mime
View raw message