So you wanna build a Flex application - Part 5 - States - ViewStacks and Getters

To date, in our series on Surfing Stats, we have covered the intent, directory structure, data sets and the main application file. (download the code using the download link at the bottom of the the Intro to Surfing Stats post). Now we examine ChartToggle.mxml.

ChartToggle.mxml

Visually, ChartToggle makes up the large content area below our TabBar. You can see the navigational choices on the left hand side, and a display section on the right containing a Table, Bar Chart or Pie Chart as appropriate.

I designed the application with a dataset (Blog Totals) that does not display well in either Bar Chart or Pie Chart format. While Surfing Stats is an academically simple application designed to teach the basic Flex concepts, I wanted to raise it a tiny bit above Fisher Price. Try it for yourself. Choose the Blog Totals tab, then choose the Bar Chart layout option.

States

States, simply put, are different modes for a component. For example, when you click a button with your mouse, the button depresses giving visual feedback. The button can be said to have an up state (raised) and a down state (depressed). In our application, ChartToggle has a normal (base) state, where all views are allowed and a nochart state, where table view is allowed but chart view is blocked.

view plain print about
1<mx:states>
2     <mx:State name="nochart">
3          <mx:RemoveChild target="{views}"/>
4          <mx:AddChild relativeTo="{uiFrame}" position="lastChild">
5        <mx:HBox id="ChartControlBox" horizontalAlign="center" verticalAlign="middle" backgroundAlpha=".2" backgroundColor="#ff0066" width="100%" height="100%">
6            <mx:Button id="ChartControlButton" label="Chart Not Available" click="chartControlClickHandler(event)" icon="{imgRemove}" width="{this.width /2}" height="{this.height * .67}" />
7        </mx:HBox>
8          </mx:AddChild>
9     </mx:State>
10</mx:states>

Reading the states code above, the nochart state removes the ViewStack containing the various views, then adds a box with a button and message.

selectedDataset and selectedDatasetAC

The selectedDataset is an object that refers to the chosen set of data. A dataset has a source, a nicely formatted title and an allowChart property. The selectedDatasetAC is an ArrayCollection containing the data from that dataset.

Remember our bound selectedDataset and selectedDatasetAC attributes in the ChartToggle configuration? In ChartToggle, the use of selectedDatasetAC is pretty straightforward. When the data inside selectedDatasetAC is changed, update the reference across our application. When the selectedDataset changes however, we gotta check to see if we can show charts. If charts are not allowed for this dataset, we need to set the nochart state. This logical intersection was a great place to show a very useful language feature of ActionScript, implicit getters and setters for properties.

view plain print about
1[Bindable] public var selectedDatasetAC:ArrayCollection;
2private var _selectedDataset:Dataset;
3
4//Logic for getting/setting the dataset object
5[Bindable]
6public function get selectedDataset():Dataset{
7    return _selectedDataset;
8}
9public function set selectedDataset(ds:Dataset):void{
10    setDisplay( ds.allowChart );
11    this._selectedDataset=ds;
12}

See the private definition for _selectedDataset? The value of the property selectedDataset is actually held there. We expose a public property selectedDataset using implicit getter/setter syntax to run logic when the public property selectedDataset is either retrieved or set. In this case, when the selectedDataset property is set, we run the setDisplay() method. We marked the public property as [Bindable] so the data will be updated should it change. (Mark either the get or the set portion as [Bindable], not both. Marking both causes an error.)

Chart Navigation

We can select a Table view, a Bar Chart or a Pie Chart. The navigation container ToggleButtonBar holds our options and is configured using mxml. We could easily have configured this using ActionScript, but we already showed how to do that for ChartConfig in Main.mxml. Note the configuration:

view plain print about
1<mx:ToggleButtonBar id="dashboardControls" itemClick="clickHandler(event)" direction="vertical" width="100%" verticalGap="30">
2    <mx:dataProvider>
3        <mx:Array>
4 <mx:Object toolTip="Table Chart" icon="{tableImage}" basedOn="table" />
5 <mx:Object toolTip="Bar Chart" icon="{barChartImage}" basedOn="chart" />
6 <mx:Object toolTip="Pie Chart" icon="{pieChartImage}" basedOn="chart" />
7        </mx:Array>
8    </mx:dataProvider>
9</mx:ToggleButtonBar>

In ActionScript, generic Objects are like structs or associative arrays. Our configured objects have a toolTip, an icon (embedded higher up in the file) and a basedOn property. Menu options that request a chart are basedOn="chart". Astute readers noticed basedOn being is used in setDisplay() to drive the proper state choice.

Display Option ViewStack

Each Navigational choice has a corresponding view. The view is contained in a ViewStack. A ViewStack contains views which are accessed by ordinal. Think of a card deck. Ask for a certain card, that card is flipped over and is now visible. The ordinal of the Button clicked by the user corresponds with a specific view in the ViewStack. Click the second (BarChart) choice, you get shown the second item in the ViewStack.

view plain print about
1private function clickHandler(event:ItemClickEvent):void {
2    setDisplay( selectedDataset.allowChart );
3 views.selectedIndex = event.index;
4}

Each value in the ViewStack is a custom component. Each component gets a height, width, id, and the selectedDatasetAC. Both charts also get a reference to an effect for events showData and hideData. The effect is a very simple SeriesSlide used to add a little snazz. Simple doesn't have to mean boring, does it? ;)

view plain print about
1<mx:SeriesSlide id="eff" duration="300" direction="right"/>

After this point, you should have learned a little about states, implicit getters/setters, navigational elements and ViewStacks. In the next series, we'll discuss the 3 display components, TableView, BarChart and PieChart.

There are no comments for this entry.

Add Comment Subscribe to Comments

1/15/08 8:59 AM # Posted By Bruce

Dan - I found a possible bug. I don't know if you can recreate it or if its my setup.

After launching the application, the applicaton is on the Blog Totals tab and the table chart is displayed.

Then I click on the Bar Chart button and get the chart not available image. Then I click back on the Table Chart button and I get a bar chart displayed in the chart panel instead of seeing the table chart.

The same thing happens if I click on the pie chart. I see the chart not available image. Then if I click back on the table chart, I see a pie chart.


1/15/08 9:21 AM # Posted By Bruce

Dan - reference the possible bug I described in my previous comment.

In charttoggle.mxml function clickHandler try putting the views.selectedIndex = event.index; first; before the call to setDisplay. In my testing that change fixed the bug.

The stack being display on top by the ViewStack component should be updated before calling the setDisplay function. That way if the if statement is false in function setDisplay and the currentState returns to the default state the correct chart will display.


1/31/08 4:13 PM # Posted By Dan Wilson

Hey Bruce,

Sorry for the delay man, I thought I commented back on this. Thanks for bringing this to my attention. There was a pretty egregious bug as you stated. I switched the calls around like you suggested and you can hardly even tell there is a bug anymore.

If I was going to fix this, I would key the changing of the display to when the selectedDatasetAC actually was loaded, rather than when the tab was clicked. That way, even if the data took several seconds to load, the process would work correctly.

I am teaching how to build this app next week so I don't think I have the time to make the changes. Maybe I can do it before 360|Flex.

Anyways, thanks for pointing this out. I knew I left one or two bugs in there somewhere....

DW