Friday, December 21, 2007

HierarchicalData from Flat XMLList data where nodes have parent info

This example shows how to make ADG display data in a Treeview or HierarchicalView when the source data is flat XMLList of nodes and each node has information about its parent node. Sample data is shown below:

<?xml version="1.0" encoding="utf-8"?>

<tasks>

<task id="1" name="Advanced Data Grid" type="parent" parentTask="0"/>

<task id="2" name="Collections" type="parent" parentTask="0"/>

<task id="3" name="OLAP" type="parent" parentTask="0"/>

<task id="4" name="Treeview" type="parent" parentTask="1"/>

<task id="5" name="Column grouping" type="parent" parentTask="1"/>

<task id="6" name="IHierarhcicalData, IGroupingCollection" type="child" parentTask="2"/>

<task id="7" name="Concrete classes" type="child" parentTask="2"/>

<task id="8" name="OLAP Interfaces" type="child" parentTask="3"/>

<task id="9" name="OLAP DataGrid" type="child" parentTask="3"/>

<task id="10" name="Charts" type="parent" parentTask="0"/>

<task id="11" name="Region selection" type="child" parentTask="10"/>

<task id="12" name="Drag drop support" type="child" parentTask="10"/>

<task id="13" name="Tree items display" type="child" parentTask="4"/>

<task id="14" name="Drag drop support" type="child" parentTask="4"/>

<task id="15" name="Column spec" type="child" parentTask="5"/>

<task id="16" name="Column drag drop" type="child" parentTask="5"/>

<task id="16" name="Column Ressize" type="child" parentTask="5"/>

</tasks>

Here each node has a parentTask attribute which specifies the parent task id. The top most nodes have parent task attribute set to zero. The nodes can be in any order.

We use the FlatXMLHD class which implements the IHierarchicalData interface to hide the XMLList parsing details. The result :

The source is available here.

Friday, December 7, 2007

Displaying GroupingCollection/HierarchicalData in Charts with drill-down

This example shows how to use GroupingCollection/HierarchicalData as dataProvider to a Chart and how to support drill down and drill up navigation.

Click on any item to drill-down and Ctrl+Click on any item to drill-up. The top chart uses HierarchicalData sample and the second chart uses GroupingCollection to generate a summary information from flat data.

Please note that all data is fictitious and I just cooked it up for the sample.

To get access to parent and children collections a HierarchicalCollectionView is constructed using GC/HD as source. To display a drilled down view the children collection is set as charts dataProvider. For a drill-up operation the clicked items parent collection is set as dataProvider.

The source can be downloaded from here.

I have used the DrillDown, DrillUp effects from Ely's chart drill down sample of XML data. The sample would have looked a bit dull without them. Thanks to Ely!.

Thursday, November 29, 2007

Use ArrayCollection available in HTTPService result with caution

Please refer to this and this bug report .

Both of them speak about data editing/update not getting propagated properly through a ArrayCollection. The samples are using the ArrayCollection available from the HTTPService result directly. The HTTPService is creating the ArrayCollection first and then updating its source Array with items. The Array object doesn't dispatch any events when it is updated with new items. Due to this ArrayCollection has no way of adding event listeners for property changes to the items added later on. Hence the changes are detected only for the items present at the time of creation of ArrayCollection which happens to be 2 items.

If one desire to use the HTTP result as dataProvider and expects data updates to get properly propagated they need to create a new ArrayCollection using the source of the default ArrayCollection present in the HTTP result.

data_provider = new ArrayCollection(ArrayCollection(srv.lastResult.data.result).source);

where srv is the HTTPService. If data_provider is already a ArrayCollection then we can just modify the source as follows

data_provider.source = ArrayCollection(srv.lastResult.data.result).source;

This bug exists in Flex 2 and may not be fixed in Flex 3 as the current bug status is deffered! The source is available here and data getting loaded here.

Customizing grouping using GroupingField.groupingFunction in GroupingCollection

It is possible to generate custom groups using groupingFunction property of GroupingField. Take a look at the following sample. By choosing different options from "Choose age range" users can view the same data in different groups.

The sample uses fictitious data of web site visitors by age and location. The example uses COUNT summary option to show how many visitors exist in each group.

The only thing to remember while writing a groupingFunction is that the return value should not change the sorting order being used for the dataField. Another way to put it is, the groupingFunction should return group names in a sorted order only. It shouldnot return group names in a random fashion.

The source can be found here.

Monday, November 19, 2007

XMLList, HierarchicalData and AdvancedDataGrid

Using a XMLList as source for GroupingCollection or HierarchicalData is a bit tricky. The trickiness comes from the fact that there are two ways to specify values for a XML node. One as attributes and second as child nodes. Depending on which way values are specified we need to set properties differently to get the desired display in ADG. For XMLList data type HierarchicalData treats the child nodes of a node to be children of the parent node by default. Specifying values as attributes:


<Parent field1="valueA" field2="valueB" >
 <Child1 field1="value1" field2="value1b" />
 <Child2 field1="value2" field2="value2b" />
 <Child3 field1="value3" field2="value3b" />
</Parent>

Here Child1, Child2 and Child3 would be recognized as children of Parent node. Specifying values as sub nodes:


<Parent>
    <field1>valueA</field1>
    <field2>valueB</field2>

   <subnodes>
    <Child1>
     <field1>value1</field1>
     <field2>value1b</field2>
    </Child1>
    <Child2>
     <field1>value2</field1>
     <field2>value2b</field2>
    </Child2>
    <Child3>
     <field1>value3</field1>
     <field2>value3b</field2>
    </Child3>
   </subnodes>
</Parent>

If above data is set as source to HierarchicalData it would treat field1, field2 and subnodes as children of Parent node, which is not correct. To tell HierarchicalData to use only the nodes under subnodes as children set HierarchicalData.childrenField to "subnodes".

The same rules apply when GroupingCollection (which is derived from HierarchicalData) is used to group flat data.

Suppose following data is used as input to GroupingCollection and grouped on Region


<Row>
    <Region>Southwest</Region>
    <Territory>Arizona</Territory>
    <Territory_Rep>Barbara Jennings</Territory_Rep>
    <Actual>38865</Actual>
    <Estimate>40000</Estimate>
</Row>

<Row>
    <Region>Southwest</Region>
    <Territory>trials</Territory>
    <Territory_Rep>Dana Binn</Territory_Rep>
    <Actual>4000</Actual>
    <Estimate>5000</Estimate>
</Row>
 
<Row>
    <Region>SouthEast</Region>
    <Territory>Central California</Territory>
    <Territory_Rep>Joe Smith</Territory_Rep>
    <Actual>5000</Actual>
    <Estimate>6000</Estimate>
</Row>

<Row>
   <Region>Southwest</Region>
   <Territory>Nevada</Territory>
   <Territory_Rep>Bethany Pittman</Territory_Rep>
   <Actual>1000</Actual>
   <Estimate>2000</Estimate>
</Row>

The result won't get displayed because the base HierarchicalData would treat <Region>, <Territory> etc nodes also as children of Row. To get proper display we need to set GroupingCollection.childrenField="abc" or some non existent node name. This would cause HierarchicalData to report that no children exist for the Row.

Friday, November 9, 2007

Smart column width based on data displayed (Part One: No code yet)

From the poll conducted I find that many users want Smart column width based on data displayed in DG/ADG.

I hope people requesting this feature know that it is a CPU intensive process to go over all the items in the dataProvider to find out maximum width required for all the columns. If the number of visible columns is more it would take even more time to compute the values and layout the columns.

If a labelFunction is being used at DG or DGColumn level and custom styles have been used on a column for fontSize for example, it complicates the computation even more.

When the data is being paged from a server it is not possible to compute the smart width at all without requesting all the data from the server, which is never desirable.

Keeping these things in mind I feel it makes sense to have a flag on individaul DGcolumn (apart from one on the DG itself) to control the computation of smart width. If the flag is true width is computed and false would use the normal way of determining the column width.

Thoughts?

Thursday, November 8, 2007

Generating summary for flat data using GroupingCollection

This example shows how GroupingCollection can be used to generate summary data for flat data and AdvancedDataGrid can be used to display the result.

The trick (or dirty work around if you like to call it so) is to generate a single dummy group using a invalid grouping field. The summary we require is specified as usual using the SummaryRow and SummaryField.

When this GroupingCollection is fed to ADG.dataProvider it would try to display in a tree view. By setting the HierarchicalCollectionView.showRoot flag to false to avoid displaying the single group parent.

By specifying the default ADGItemRenderer as ADG.groupItemRenderer we can prevent the group icons from getting displayed.

The source is here.

Please note I have not tested this example extensively. So some bug fixes may be required before it can be used in production.

Friday, November 2, 2007

Customizing Group label fields when using GroupingCollection

By using the ADG.groupLabelFunction property one can customize the group label displayed for the group nodes. The following example shows how children count can be displayed as part of the group label when the group is closed. The source can be found here.

Friday, October 12, 2007

Poll for current and new features in AdvancedDataGrid

I created three polls at the end of my blog. One to know how users are feelling about ADG in its current form, second what features of ADG in Flex 3 users are liking the most and third one to see what new features users would like to see in the next version of AdvancedDataGrid to make it more useful.

Who knows you may be able to guide the future developement of ADG !

Thanks in advance for giving your opinion!

If you want to see more choices do leave a comment. I would add it.

Thursday, October 11, 2007

Async refresh of GroupingCollection

In Flex 3 Beta-2, GroupingCollection adds support for asychronous refresh. When we have large number of input rows or don't want to wait for the grouping to finish to see the results we can pass true to GroupingCollection.refresh(async:Boolean) and get to view the results as the grouped data is built. Users are allowed to interact with the shown information. Refresh can be even stopped by calling cancelRefresh.

I wrote a small app to test this. The app generates random data and displays it in AdvancedDataGrid(ADG) when "Populate ADG" is clicked. The number of data rows can be modified using the numeric stepper. A click on "Group" starts async refresh and ADG starts displaying the results immediately. Grouping can be cancelled any time using "Cancel Grouping". The three check boxes allow different combinations of grouping to be performed.

Option to pause/resume a refresh is not available.

The source is available here.

Friday, September 28, 2007

Displaying charts in AdvancedDataGrid

Using charts as itemRenderers in DG and ADG is easy. Find the sample files here The sample uses a LineChart as itemRenderer for the third column and a PieChart in the child area. The column-spanning option available through RendererProviders is used to make the PieChart occupy the whole row. The sample shows use of HierarchicalData but even without that All chart types can be used as itemRenderes.

Monday, August 27, 2007

AdvancedDataGrid Multi level Column Grouping

AdvancedDataGrid supports column grouping. An example showing multiple level grouping is shown below. Here is the mxml file.

Tuesday, July 31, 2007

Customizing headers in DG/ADG

Customizing headers in DataGrid and AdvancedDataGrid (DG/ADG) is very easy. Just point the headerStyleName property available on these controls to any style declaration you want. The following image shows one such example where the header text is colored in blue and red. The second column text is center aligned. The important thing to notice here is that the headers are now styled differently than the column content. If the same styles were set on the column objects then the header as well as column content would have got same styles. headerStyleName allows customizing only the headers. The headerStyleName is available on the control and the column object. Hence you can set the control.headerStyleName to customize all the headers and use the column.headerStyleName to customize individual headers. A sample mxml file.

Thursday, June 21, 2007

Using public namespace explicitly

Having same function in two or more name spaces can cause the following compiler error when trying to access the function. 1000: Ambiguous reference to foo. This error is easily generated when "using namespace " has been included in the file instead of referring to the namespace explicitly.
myspace.as

package
{
  public namespace myspace = "http://myspace";
}

TestClass.as

package
{
import myspace;

public class TestClass
{

  public function foo():void
  {
 trace("Public foo is called");
  }

  myspace function foo():void
  {
 trace("MySpace foo is called");
  }

  private function fooPrivate():void
  {
 trace("Called private function");
  }

  protected function fooProtected():void
  {
 trace("Called protected function");
  }

  public function callFoo(t:TestClass):void
  {
        // call the private/protected members on the object.
 t.fooPrivate();
 t.fooProtected();
  }
}
}

testApp.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
 creationComplete="testFunc()">
<mx:Script>
 <![CDATA[

use namespace myspace;

private function testFunc():void
{
   var test:TestClass = new TestClass;
   //public can be also used as namespace name to call the correct function.
   test.public::foo();

   // call the myspace namespace function
   test.myspace::foo();

   var test2:TestClass = new TestClass;
   // call the function to demonstrate that private/protected functions
   // can be called on test2 object.
   test.callFoo(test2);

}
]]>
</mx:Script>
</mx:Application>
The above example also shows the possibility of calling private/protected functions on an object of the same class within the functions of the class. I don't think this is allowed in languages like C++. Note: As Richard has commented it is alllowed in C++ too. I think it makes sense as friend functions can access private variables of objects member functions should be able to access them too.

Tuesday, June 19, 2007

Summary customization in AdvancedDataGrid

ADG allows customization of Summary and Grouping with various callback functions and properties. One such property available on the SummaryField class is the label property which allows one to customize the property name used for the summary data. This example shows one such usage to skip displaying any estimate information at the leaf level but display a budget summary data at the Territory level. The mxml file is here.

Thursday, June 14, 2007

headerStyleName property of AdvancedDataGrid

In my previous post I said that I thought it was not possible to style the header independent of the column cells. I was wrong. I found out that AdvancedDataGrid has the headerStyleName property similar to DG which can be set and headers can be styles independently. Using that and tweaking a little bit of code I could get the following look and feel which looks really nice!

AdvancedDataGrid Summary with column grouping

I improved my previous sample with column grouping getting the following look. The new MXML can be found here. One problem I immediately noticed is that one cannot horizontally center the headerText of the columns without centering the column cell text, this is specially a problem with first column. I filed a request for this. The headerText cannot be vertically centered either. However this has been already reported requesting even more options.

AdvancedDataGrid Summary roll up sample

Here is a sample application showing Summary roll up feature in AdvancedDataGrid and GroupingCollection. The GroupingCollection takes flat data in the form of a ICollectionView object as input and generates a grouped collection based on the GroupingField information provided. The example shows grouping on the Region and Territory data fields. Of-course don't forget to call the refresh method on the GroupingCollection to make the collection to generate the grouping. If Summary is desired Summaries with SummaryRow and SummaryField information can be added to each GroupingField object. The SummaryRow has a summaryPlacement property which can take multiple values as input from the possible values of group, first and last. I have used group to show the roll up of summary values. SummaryField has a operation property which by default supports "SUM", "MIN", "MAX", "AVG" and "COUNT". ADGColumn has support for a formatter which can be used to format cell values using any Flex formatter. I have used currency formatter to place a $ symbol. ADG and ADGColumn have a style function property which can be used to set style values on a particular cell based on its data content. The example uses this to change the font color to red. Oh! ADG has loads of features. Check it out. Before I forget here is MXML file for the sample.

Friday, May 25, 2007

Flex components to PDF

Printing Flex components or converting them to PDF is very easy. Here is a sample code which shows how to print a column chart. If you want to generate a PDF you need to have ADOBE PDF printer driver installed on the machine. In the print dialog instead choosing a printer you can choose ADOBE PDF printer listed and you get a PDF as output. Sunil has more info about printing charts with data tips here. More about Flex Printing can be found here too. ChartToPDF.mxml

Wednesday, March 14, 2007

Specifying children for derived MXML containers can be done at only one place

Error: Multiple sets of visual children have been specified for this component (component definition and component instance). is thrown by Flex when developers attempt to define children at two different places for a container. Suppose we have MyFirstBox extending HBox as follows: MySecondHBox.mxml
   <mx:HBox mx="http://www.adobe.com/2006/mxml">

      <mx:Button label="Button in declaration"/>
 
   </mx:HBox>
And we are trying to use MyFirstBox in another container like this
  <Application>

    <MyFirsthBox>

      <mx:Button label="Button in Instance" />

    </MyFirstHBox>
  </Application>
Flex throws the exception because it finds that in the declaration as well as in the instance inside the application child buttons are being added. This may be very easy to catch but where it bites is when we are trying to create a hierarchy of MXML components. Suppose we try to create a second HBox derived from MyFirstBox as follows MySecondHBox.mxml
  <MyFirstHBox xmlns="*" mx="http://www.adobe.com/2006/mxml">

    <mx:Button label="Button in derived comp" />


  </MyFirstHBox>
This is also not allowed as it falls under the same category and Flex throws the same exception. The workaround is to define children only in the leaf derived class. Any solution?

Sunday, March 4, 2007

Coding problem in ActionScript

The following code generates a VerifyError when getInstance is called. VerifyError: Error #1030: Stack depth is unbalanced. 0 != 1. at SingletonTest$iinit() public class SingletonTest { private static var s_singleton:SingletonTest = null; public static function getInstance():SingletonTest { if (s_singleton == null) s_singleton = new SingletonTest(); //Fails at this line. return s_singleton; } public function SingletonTest() { super; try { } catch (e:Error) { } } } Can you guess why? The reason is the super call in the constructor which is missing the () ! Why wouldn't the compiler throw a error or ignore the statement?

Friday, February 23, 2007

ResourceBundle Tag should match the name of properties file

Unable to resolve a class for ResourceBundle: xxx.

is a very frequent error thrown by the MXML compiler when we are including different SWCs as libraries or trying to create a new resource by creating a new yyy.properties file and trying to use it in a AS class file by using the [ResourceBundle] tag. The key is to remember that the name given in the tag should match the properties file name. So for yyy.properties file one should use [ResourceBundle("yyy")] . Even if you are using a zzz_rb.swc file containing the resources and you want to use the yyy resource present in the swc we should use the [ResourceBundle("yyy")] tag in AS file.

Saturday, February 17, 2007

About Flex

I joined Macromedia (now Adobe) in 2005 July after spending more than 7 years in Tata Elxsi. I opted to switch from Maya, 3D Graphics, C++ programming to Flex, ActionScript and Player. After learning about blogging from Manish and reading blogs from Ely, Kevin Lynch, Raghu and various other people I also wanted blog separately on Flex but never thought my knowledge enough to enough to write one. After a year or so I am feeling that I could put together a blog with lot of "pearls" I keep picking up from the DL-Flex Questions mailing list so that including myself anyone can make use of these.