11 Replies Latest reply on Jul 26, 2007 12:04 PM by schjlatah

    Passing variables between mxml components

    10basetom
      Hi guys,

      I'm just getting started in Flex, using the Dashboard sample app as my training ground:

      http://www.adobe.com/devnet/flex/samples/dashboard/


      For anyone not familiar with this sample app, here's the basic layout:


      • dashboard.mxml - main application that calls AllRegions.mxml, RegionDetail.mxml, and RegionBreakdown.mxml
      • RevenueTimeline.mxml - provides chart class
      • AllRegions.mxml - subclass of RevenueTimeline that instantiates chart
      • RegionDetail.mxml - subclass of RevenueTimeline that instantiates chart
      • RegionBreakdown.mxml - pie chart panel


      My goal is very simple: I've declared a variable in dashboard.mxml that contains the string "Revenue":

      quote:


      public var timeline:String = "Revenue";


      All I'm trying to do is access this 'timeline' variable from within the RevenueTimeline, AllRegions, RegionDetail, and RegionBreakdown components. Right now "Revenue" is hard-coded everywhere (e.g., tool tips, column header in grid view), so was trying to do something like this instead:

      quote:


      private function formatDataTip(hitData:HitData):String
      {
      var name:String = hitData.item.name;
      var revenue:Number = hitData.item.revenue;
      return "<b>Month: " + name + "</b><br>' + timeline + ': " + cf.format(revenue);
      }


      What's holding me back is that I can't seem to find a way to pass the variable that I declared in dashboard.mxml to all of the other four components (RevenueTimeline, AllRegions, RegionDetail, RegionBreakdown). I'm at the end of my rope here, so I was hoping someone can offer a quick solution or lead me in the right direction. I've read about view states, but it seems a little over the top for me; I'm not changing layouts depending on states or anything.

      After finding out how to change the tool tips to use the 'timeline' variable, my next goal is to also leverage this variable for the column headers in the grid view. For example, I would like to use my variable instead of hard-coding "Total Revenue" in the code below:

      quote:


      <mx:DataGridColumn dataField="name" headerText="Month" sortCompareFunction="sortByDates" />
      <mx:DataGridColumn dataField="revenue" headerText="Total Revenue" labelFunction="dataGridCurrencyFormat" />
      <mx:DataGridColumn dataField="average" headerText="Average Across Categories" labelFunction="dataGridCurrencyFormat" />


      Does anyone know how I can set an mx tag attribute value to an an ActionScript variable? If that's not possible, then what is the simplest solution to do what I'm trying to do (use 'timeline' variable defined in dashboard.mxml instead of hard-coding "Total Revenue" in tool tips and column headers in grid view)?

      TIA!
      Tom
        • 1. Re: Passing variables between mxml components
          davidmedifit Level 1
          Tom,
          What you want to do is define a "setter" in your custom component. I am going to assume that your custom component is a datagrid, but it may not be - that's kind of irrelevant to the code I'll post next anyway.

          Code for component:

          <mx:Script>
          <![CDATA[
          [Bindable] private var _timelineString:String;

          public function set timelinePeriodSet(itemString_value:String):void
          {
          _timelineString= itemString_value;
          }
          ]]>
          </mx:Script>

          The declaration of your bindable variable can be public or private, depending on what you want to do with it (I put it as private, for an example)

          You will want to reference this variable in your custom component in the following manner (borrowing from your code):
          ..
          <mx:DataGridColumn dataField="revenue" headerText="{_timelineString}" labelFunction="dataGridCurrencyFormat" />
          ..

          NOW, that's the component sorted out, you want to pass that value into the component from the application in the first place.
          I will assume your component is defined in a namespace of "components".

          Code:
          <components:my_custom_dataGrid id="myDG" timelinePeriodSet="{timeline}"/>

          There may be some bugs/typo's in the above code (I didn't test it in FB before I posted), but it will set you in the right direction.

          Post back if you have any further questions.

          Cheers,

          David
          • 2. Passing variables between mxml components
            10basetom Level 1
            Thanks, David! I'm trying to digest what you gave me. Could you please clarify this code:

            <components:my_custom_dataGrid id="myDG" timelinePeriodSet="{timeline}"/>

            What does {timeline} represent? I did not see it declared in your code so was confused.

            After posting my question I found a way to pass variables to the other components by doing this:

            dashboard.mxml:
            ...
            [Bindable]
            public var timelineString:String = "Revenue";
            ...
            <AllRegions id="allRegions" testString="{timelineString}" ... />
            <RegionBreakdown id="regionBreakdown" testString="{timelineString}" ... />
            <RegionDetails id="regionDetails" testString="{timelineString}" ... />
            ...

            RevenueTimeline.mxml:
            ...
            [Bindable]
            public var testString:String;
            ...

            AllRegions.mxml:
            <RevenueTimeline ...>
            ...
            private function formatDataTip(hitData:HitData):String
            {
            var name:String = hitData.item.name;
            var metric:Number = hitData.item.revenue;
            return "<b>Month: " + name + "</b><br>" + testString + ": " + cf.format(revenue);
            }
            ...
            </RevenueTimeline>

            HOWEVER, I'm still not able to access 'testString' from within RevenueTimeline.mxml. The data grid component also happens to exist in RevenueTimeline.mxml. So, first I need to figure out how to access 'testString' from within RevenueTimeline, then I'll need to figure out how to replace the hard-coded "Total Revenue" with something like "Total " + testString for the code below:

            <mx:DataGridColumn dataField="revenue" headerText="Total Revenue" labelFunction="dataGridCurrencyFormat"/>

            Tom
            • 3. Re: Passing variables between mxml components
              10basetom Level 1
              Hi guys,

              After much mucking around with the code I finally got it to do most of what I wanted. However, I have come to another obstacle I have not been able to overcome. Here is the basic setup:

              app.mxml - main app
              panel.mxml - component called from app.mxml
              chart.mxml - contains charting class used by panel.mxml

              - In app.mxml you have the option to select currency format or number format, and your selection is saved in a bindable variable called chartOption that is passed on to panel.mxml.

              - panel.mxml instantiates a chart object provided by chart.mxml. The chart contains <mx:LinearAxis ... labelFunction="formatNumber">, where formatNumber is a function defined in chart.mxml. I would like this function to either format the axis labels as currency or plain numbers depending on what option was selected in app.mxml; however, I'm not able to pass the chartOption variable declared in app.mxml to chart.mxml. The formatNumber function needs to access this variable to decide whether to format the axis as currency or number.

              I hope everything makes sense. My goal seems simple enough, but yet I'm having such a hard time with this one. I've figured out how to pass variables from module to module in Perl and PHP without a sweat, but ActionScript 3 is kicking my butt right now. Any insights would be much appreciated.

              Thanks,
              Tom
              • 4. Re: Passing variables between mxml components
                ntsiii Level 3
                Pass it to panel first then from there to chart.

                Or reference the value from chart using Application.application.

                Tracy
                • 5. Re: Passing variables between mxml components
                  10basetom Level 1
                  Hi guys,

                  Christopher from actionscript.org gave me a suggestion that works great for what I'm trying to do: put my global strings in a separate AS package file. You can read more about it here:

                  http://www.actionscript.org/forums/showthread.php3?p=563454

                  Thank you everyone who took the time to respond, it has been a great learning experience.

                  Tom
                  • 6. Re: Passing variables between mxml components
                    schjlatah Level 1
                    Tom,
                    When I came up against this a couple of months ago I just created a custom Event type with all the variables I wanted to throw back to the main MXML, dispatched it from my component, then wrote a little Event handler to handle my custom event.
                    I don't know if that is the right way to do it, but it is the way that has worked for me.
                    • 7. Re: Passing variables between mxml components
                      ntsiii Level 3
                      "...custom Event type ...
                      This is considered "best practice"
                      Tracy
                      • 8. Re: Passing variables between mxml components
                        10basetom Level 1
                        interesting, i've never created custom events before. i'll have to play around with that.

                        thanks for the input,
                        tom
                        • 10. Re: Passing variables between mxml components
                          dkerr
                          What about passing dynamic object data from one mxml component to another?

                          For example,
                          In main.mxml application
                          When a user selects a row in mydataGrid contained in entrylistview.mxml component page
                          my viewstack changes to show readentryview.mxml
                          readentryview.mxml contains another viewstack within it and loads entryview.mxml component page
                          entryview.mxml displays the selected entry content

                          In english, it is like an inbox, when a message is selected, the inbox wipes away and the selected message view wipes.

                          Problem I'm having is passing entryList.selectedItem object to the entryview, when my viewstacks are nested like below...

                          Main.mxml Application
                          <mx:ToggleButtonBar id="loopmenu" height="100%" dataProvider="{loopViews}"/>
                          <mx:ViewStack id="loopViews" width="100%" height="550" creationPolicy="all">
                          <entrylistview id="Entries" label="Blog Entries" showEffect="WipeLeft" hideEffect="WipeRight"/>
                          <readentryview id="readentry" label="Read Entry" enabled="false" showEffect="WipeLeft" hideEffect="WipeRight"/>
                          ...
                          </mx:ViewStack>

                          readentryview.mxml component
                          <mx:ToggleButtonBar id="loopmenu" height="100%" dataProvider="{entryViews}"/>
                          <mx:ViewStack id="entryViews" width="100%" height="550" creationPolicy="all">
                          <entryview id="entry" label="Entry" showEffect="WipeLeft" hideEffect="WipeRight"/>
                          <commentlistview id="Vcommentlist" label="Comments" showEffect="WipeLeft" hideEffect="WipeRight"/>
                          <newcommentview id="Vnewcomment" label="New Comment" showEffect="WipeLeft" hideEffect="WipeRight"/>
                          <...
                          </mx:ViewStack>

                          Using parentDocument dot syntax worked great when the viewstack was not in readentryview.mxml...
                          public function showReadentry():void {
                          parentDocument.loopViews.selectedIndex=5;
                          parentDocument.readentry.enabled = true;
                          var selectedentry:Object = entryList.selectedItem;
                          parentDocument.storeVars.selectedentryobj = selectedentry;
                          }
                          But it no longer works with the nested viewstacks.

                          I was hoping there is a way to simple use the mxml component name I want to pass it to, like
                          main.storeVars.selectedentryobj = selectedentry
                          readentryview.storeVars2.selectedentryobj = selectedentry
                          or something like that.

                          To create my mxml components, I simply went to file new and selected mxml component, instead of mxml application. Do I need to do something else for I can reference the component name in a dot syntax?

                          Thanks,
                          Don



                          • 11. Passing variables between mxml components
                            schjlatah Level 1
                            Don,
                            In stead of referencing parentDocument.whatever you could try throwing a custom event that doesn't need to be of a special type. Here is a link to the LiveDoc about dispatching custom events: Link
                            Your best bet would be to throw custom events typed as a custom class that extends Event and keep all the data you want in it, then using that event to pass the data back, and you could also fire off your change viewstack selectedIndex function on the result handler. Or you could go with a Singleton Data Model, but I've never liked those.

                            Then to pass that data down to the child components, try using a setter method as described in davidmedifit's posting higher up on this page.