1 Reply Latest reply on May 7, 2008 12:25 PM by ntsiii

    Updating components when data changes

    mslinn Level 1
      I am having trouble getting a set of components to update when data is modified by another set of components.

      A com.adobe.cairngorm.model.IModelLocator is used to hold the model data; the concrete class is called ViewModelLocator. Code that needs to access the data does so via the following declaration in the relevant ActionScript files:
      private static var app:ViewModelLocator = ViewModelLocator.getInstance();

      One of the data members of the model is a rather complex class called Species, defined in com.micronauticsresearch.ewConfig.model.empathyWorks.Species.as. An instance of the Species class is used by composition in another class called an Individual, defined in com.micronauticsresearch.ewConfig.model.empathyWorks.Individual.as

      I have created a set of custom components that provides editing support for a Species instance. These components are defined in MXML and referred to as TripleSlider components by the following namespace:
      xmlns:TripleSlider="com.micronauticsresearch.ewConfig.view.tripleSlider.*"

      TripleSliders generate a 'change' event whenever a user adjusts their controls. I have reused SliderEvent for this purpose:
      <mx:Metadata>
      [Event(name="change", type="mx.events.SliderEvent")]
      </mx:Metadata>

      Species are rendered from com.micronauticsresearch.ewConfig.view.prlEditor.SpeciesTendencies.mxml as follows:
      <fc:FlowContainer
      height="100%"
      horizontalCenter="true"
      width="100%" >
      <mx:Repeater id="rp" dataProvider="{app.species.tendencies.keys()}">
      <TripleSlider:tripleSlider
      attributeName="{rp.currentItem}"
      clusterValue="{tendencyClusterValue(rp.currentItem)}"
      defValue="{attributeDefaultValue(rp.currentItem)}"
      minValue="{attributeMinValue(rp.currentItem)}"
      maxValue="{attributeMaxValue(rp.currentItem)}"
      showLimits="false"
      change="valueCommit(event)" />
      </mx:Repeater>
      </fc:FlowContainer>

      I wrote some custom collection classes; app.species.tendencies is a TreeMap (patterned after Java's TreeMap.) Individuals are rendered from com.micronauticsresearch.ewConfig.view.virtualWorld.IndividualAttribures.mxml as follows:
      <FlowContainer:FlowContainer
      height="100%"
      horizontalCenter="true"
      width="100%" >
      <mx:Repeater id="rp" dataProvider="{app.individual.attributes.keys()}">
      <TripleSlider:tripleSlider
      showLimits="true"
      attributeName="{rp.currentItem}"
      minLimit="{app.individual.species.tendencies.getItem(rp.currentItem as String).minValue}"
      maxLimit="{app.individual.species.tendencies.getItem(rp.currentItem as String).maxValue}"
      defValue="{app.individual.limits.getItem(rp.currentItem as String).defValue}"
      minValue="{app.individual.limits.getItem(item as String).minValue}"
      maxValue="{app.individual.limits.getItem(item as String).maxValue}}" />
      </mx:Repeater>
      </FlowContainer:FlowContainer>

      app.individual.attributes is also a TreeMap. The attributes are recomputed when the Species is edited so the Individual's TripleSliders can be updated. Unfortunately my choice of an iterator for rendering Individual attributes appears to be unhelpful because the keys do not change; the values change instead. Seems like my choices are:
      1) Modify app.individual.attributes to be an ArrayList (another Flex class I created which models a Java collection); the data binding for Individuals should then trigger a refresh.
      2) Set up one or more listeners in IndividualAttributes.mxml, listening for the 'change' event dispatched by the Species TripleSlider; I'm unsure of how I should approach this.
      3) ... any other approaches?

      Here is a failed attempt at forcing at update by providing a bogus parameter. Not sure why it did not work:
      <mx:Script>
      <![CDATA[
      internal function minLimit(item:Object, bindingTrigger:TendencyList):int {
      return app.individual.species.tendencies.getItem(item as String).minValue;
      }
      ]]>
      </mx:Script>
      <mx:Repeater
      id="rp"
      dataProvider="{app.individual.attributes.keys()}">
      <TripleSlider:tripleSlider
      showLimits="true"
      attributeName="{rp.currentItem}"
      minLimit="{minLimit(rp.currentItem, app.species.tendencies)}"
      maxLimit="{maxLimit(rp.currentItem, app.species.tendencies)}"
      defValue="{currentValue(rp.currentItem)}"
      minValue="{minValue(rp.currentItem)}"
      maxValue="{maxValue(rp.currentItem)}" />
      </mx:Repeater>
      </FlowContainer:FlowContainer>

      Mike

      BTW, the following syntax seems like it might be a convenient shorthand, but it is not legal. Perhaps a future version of ActionScript might support an implied destination?

      <TripleSlider:tripleSlider
      showLimits="true"
      attributeName="{rp.currentItem}"
      minLimit="{minLimit(rp.currentItem, app.species.tendencies)}"
      maxLimit="{maxLimit(rp.currentItem, app.species.tendencies)}"
      defValue="{currentValue(rp.currentItem)}"
      minValue="{minValue(rp.currentItem)}"
      maxValue="{maxValue(rp.currentItem)}" >
      <mx:Binding source="app.individual.species.tendencies" />
      </TripleSlider:tripleSlider>
        • 1. Re: Updating components when data changes
          ntsiii Level 3
          what is:
          app.individual.attributes.keys()

          is keys() a method? You can bind to methods, but they require some changing property in order to fire binding.

          Binding requires either an ArrayCollection, XMLListCollection, or XML. Array, and XMLList are not bindable.

          If you are bound to one of those, and use the appropriate API to do the update, then bound UI element will update.

          Tracy