In Lesson 10, “Using DataGroups and Lists,” you worked with datasets and some controls that can be used to show the data. In this lesson, you will build on that set of base controls and be introduced to the primary MXML component used to display and manipulate large datasets.
In this lesson, you will learn how to use the DataGrid component to display a dataset in an interactive way using rows and columns. Aside from using the DataGrid in its simplest form, you will learn how to override the default behavior of a particular column in the DataGrid by implementing a custom item renderer; do a custom sort of the data in a column; and change the editing controls that manage the underlying data. You will also use the sorting, styling, grouping, and summary data features of the AdvancedDataGrid.
So far in this book we have managed to ignore a fundamental aspect of developing in Flex, which is the use of multiple component sets. Flex 4 is the first version of Flex to have more than one set of components, meaning that there are really two types of Labels, two types of Buttons, and two types of TextInputs, among other controls. These two types are referred to as MX and Spark.
The MX set of controls has been under constant evolution since Flex 1.0. The same basic controls, with the same metaphors, have slowly developed over a number of releases. This set of controls worked primarily through the object-oriented concept of inheritance, meaning that if you wanted a control to behave in a new way, you extended the previous control and changed some portion of its functionality.
Spark is a brand-new set of controls making their first appearance in Flex 4. In the Spark set of controls, components are built through the concept of composition. You have actually been working with this all along. When you wanted a group to be horizontal or vertical, you combined the Group with a HorizontalLayout or VerticalLayout. This is composition.
While Spark is the future of Flex, it is not all-encompassing yet, meaning that the many years of development that went into developing the MX component produced a component set with huge diversity and functionality. Spark has had much less development time, so while it performs extremely well, it does not have breadth of function that MX has today.
Therefore in Flex 4, we combine Spark and MX controls to achieve what we desire. Whenever possible, we embrace Spark components, as they are easier to customize, are often more performant, and will be the focus of continuing improvements. When Spark does not have a feature we need yet (such as the Form, DataGrid, and AdvancedDataGrid), we use the MX versions, which integrate nicely with Spark and allow us to complete our component set.
Using a DataGrid as a way to display the data of your application provides the largest possible number of options for your users to interact with the data. At the simplest level, the DataGrid organizes the data in a column-by-row format and presents this to the user. From there, the DataGrid can be configured to allow you to modify the data it contains.
In this lesson, you will make modifications to FlexGrocer, in which the DataGrid will give you a view of the cart and the ability to both update and remove items from the cart.
Although the DataGrid does provide the most versatile manner of interacting with the data of your application, it does come with additional overhead (performance and size). It is wise to consider what you expect the user to do with the data or controls before you automatically choose to use a DataGrid.
When you left off in Lesson 11, “Creating and Dispatching Events,” you had the contents of your cart displayed in a List control with the ability to remove the current item you were viewing via a Remove From Cart button. You will now use a DataGrid to display the contents of the cart. The DataGrid control supports the syntax that allows you to specify the columns explicitly through the DataGridColumn:
<mx:DataGrid ... >
<mx:columns>
<mx:DataGridColumn dataField=""...>
<mx:DataGridColumn...>
<mx:DataGridColumn...>
</mx:columns>
</mx:DataGrid>
The dataField
is used to map a property in the dataset to a given column. The order in which the DataGridColumns are listed is the order you will see the columns from left to right in the DataGrid. This is useful when you need to specify a different order of the columns from the one specified in the dataset. Each DataGridColumn supports a large number of attributes that affect the DataGrid’s rendering and interaction with the given column.
Alternatively, if you didn’t complete the previous lesson or your code is not functioning properly, you can import the FlexGrocer.fxp project from the Lesson12/start folder. Please refer to Appendix A for complete instructions on importing a project should you ever skip a lesson or if you ever have a code issue you cannot resolve.
<mx:DataGrid>
tag, add the editable
property and assign it the value true
.You are specifying editable
as true
because you will allow one of the columns to be changed by the user. If it is set to false
, the whole DataGrid becomes read-only.
<mx:DataGrid xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
editable="true">
<fx:Declarations>
tag set, define an <mx:columns>
tag set.You will be adding DataGridColumn objects in the next steps, and they need to be nested in the columns tag set.
<mx:columns>
tag set, define an <mx:DataGridColumn>
for the product name. Set the headerText
to Product
, dataField
to product
, and editable
to false
.<mx:DataGridColumn headerText="Product" dataField="product" editable="false" />
The headerText
attribute specifies the text of the DataGridColumn header. If you don’t specify this, it will take the value of the dataField
attribute.
Because the editable
attribute is set to true
on the <mx:DataGrid>
tag, you need to set it to false
for each column you don’t want to use for editing.
<mx:DataGridColumn>
for displaying the quantity, and place it after the last <mx:DataGridColumn>
. Set headerText
to Quantity
and dataField
to quantity
.<mx:DataGridColumn headerText="Quantity" dataField="quantity" />
This column will be used to allow users to change the quantity of a specific product they want to buy.
<mx:DataGridColumn>
for displaying subtotals for each item and place it after the last <mx:DataGridColumn>
. Set headerText
to Amount
, dataField
to subtotal
, and editable
to false
.<mx:DataGridColumn headerText="Amount" dataField="subtotal" editable="false" />
<mx:DataGridColumn>
for displaying a Remove button. At this point only set editable
to false
.<mx:DataGridColumn editable="false" />
Later you will add functionality so a button will remove the item in a particular DataGrid row.
You’ve created the basic component that uses a DataGrid to display data in the shopping cart data structure. Now you will replace the placeholder DataGrid that was inserted earlier with the newly created component.
<mx:DataGrid>
block near the bottom of the file and remove it.<components:CartGrid>
component. Set the id
to dgCart
, the includeIn
to cartView
, and the width
and height
to 100%
.dataProvider
to shoppingCart.items
.<components:CartGrid id="dgCart"
includeIn="cartView"
width="100%" height="100%"
dataProvider="{shoppingCart.items}" />
You should see the DataGrid with some data in it. At this point the information is not formatted correctly, but you see that the component is being used and data is being passed to CartGrid. Note the Product column is showing up as text in the DataGrid, even though it is a complex attribute in the dataset. This is because there is a toString()
function declared on the Product value object. If this weren’t defined, you would see [Object Product]
. You will look at how to better display a complex object later. For now, this is what you should see:
In a DataGrid, you can specify that a column of the data shown can be changed by the user when focus is brought to the cell. This is done by setting the editable
attribute to true
. The default editing control for the column is a text field. It is possible to specify which editor to use when managing the data via the itemEditor
attribute and the editorDataField
. The editorDataField
specifies the attribute of the editing control used to manage changing the value for the cell, as well as which attribute on that control the dataset should examine to get the changed value. The following are the built-in controls from the MX package that you can specify (full package names are needed unless the controls are imported into the containing page):
As mentioned, in Flex 4 you can use controls from the MX and Spark packages together. The DataGrid is from the MX package and has been designed to easily integrate with other controls from the MX package. When specifying an itemEditor, the DataGrid will automatically work with any of these built-in controls, as they all implement an interface named IDropInListItemRenderer
.
You can also specify your own controls built from pieces of either the MX or Spark packages if you desire. Your new control simply needs to implement the IDropInListItemRenderer
interface in its class definition to work.
<mx:DataGridColumn>
tag that maps to the quantity, set the itemEditor
to mx.controls.NumericStepper
, set editorDataField
to value
.<mx:DataGridColumn headerText="Quantity"
dataField="quantity"
itemEditor="mx.controls.NumericStepper"
editorDataField="value" />
This now has the Quantity column being edited as an MX NumericStepper. The NumericStepper control lets the user select a number from an ordered set. The underlying value of the column is bound to the value
attribute of the NumericStepper.
When you click in the Quantity column, you will notice that it doesn’t open as a freeform text field, but rather as a NumericStepper control.
The default behavior of the DataGrid is to convert every value of the dataset to a string and then display it. However, when you are dealing with a complex object that is stored in the dataset, another alternative is to create a custom item renderer that shows more information about the column. In this case, you are going to create a simple item renderer that shows the product’s name and image.
When working with item renderers, you will find that there is an implicit public variable available to you in the item renderer called data
, which represents the data of the row itself. You can use data
to bind your controls without having to worry about what column you are working with. When the DataGrid creates a column that has a custom item renderer associated with it, it creates a single instance of the cell renderer per row, so you don’t have to worry which row of data you are working with in a renderer.
You have been using Spark components over MX components whenever possible. Although there is no Spark DataGrid, you will still use Spark components when possible in the item renderers. You will use the <s:MXItemRenderer>
as the base tag for your item renderers. This class lets you use the Spark item renderer architecture with MX DataGrid.
This MXML file will define the layout of a given cell in the DataGrid. You are creating it in a separate file so that, if needed, it can be used on multiple DataGrid columns and/or multiple DataGrids.
<s:MXItemRenderer>
, set the clipAndEnableScrolling
attribute to true
.<s:MXItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
clipAndEnableScrolling="true">
This will ensure that none of the contents of the item renderer extend past the boundaries of the renderer.
<mx:Image>
tag below the <fx:Declarations>
tag set to display the product’s thumbnail image. You need to set the source
attribute to a hard-coded directory location, but the filename should be bound to the imageName
of the product object. That will make it look like {'assets/' + (data.product as Product).imageName}
. Also assign the width
the value of 100
.<mx:Image source="{'assets/' + (data.product as Product).imageName}" width="100"/>
The image location used is relative to the location where the main application is loaded from, not the location of the file that contains the <mx:Image>
tag.
It is worth mentioning here that you could have referred to the image name simply as data.product.imageName
. You might have already noticed the first advantage of casting the object as type Product, and that is the code-completion supplied the imageName
property when you were typing the code. This would not have happened if you had not done the casting.
The next advantage is even more important if you ever make changes to the Product object. The refactoring tools now available in Flash Builder enable you to change the name of the imageName
property if you should ever want to. The reference is automatically updated because it is a property of the Product object. Again, this will not happen if you do not do the casting.
<s:Label>
tag for the product name below the <mx:Image>
tag. Bind the text
attribute to ( data.product as Product ).prodName
. Set the height
and width
to 100%
.<s:Label text="{( data.product as Product).prodName}" width="100%" height="100%"/>
You cannot test this component at this time because it is not yet assigned to the DataGrid.
<mx:DataGridColumn>
with a dataField
of product
with a new attribute, itemRenderer
, set to components.ProductName
.<mx:DataGridColumn headerText="Product"
dataField="product"
editable="false"
itemRenderer="components.ProductName" />
With the use of the itemRenderer
attribute, you are overriding the default TextInput editor. You need to use the fully qualified class name to set your item renderer unless you have imported the class package that it exists in.
<mx:DataGrid>
with a new attribute variableRowHeight
set to true
.<mx:DataGrid xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
editable="true"
variableRowHeight="true">
It is necessary for you to set the variableRowHeight
to true
so that Flex resizes the row’s height to accommodate the thumbnail image.
Another option for creating an item renderer is through the <mx:itemRenderer>
tag, which allows you to declare and create the item renderer inline with the DataGridColumns. From a compiler perspective, doing an inline item renderer is the equivalent of building it in an external file (it actually compiles the code of the inline item renderer as a separate file internally). Inside the <mx:itemRenderer>
tag, you will place an <mx:Component>
tag, which defines the boundaries of the inline item renderer file from the rest of the page. Thus, the inside of the <mx:Component>
tag will have its own scope for which you will need to do imports, function declarations, and the like.
Although building inline item renderers will be very efficient from a coding perspective, it does not allow you to reuse the item renderers for other DataGrids. Good candidates are item renderers that are specific to one DataGrid only, such as action item controls.
Just like the item renderer you created in the previous exercise, this one will have access to the data
variable, which will hold the reference to the row. For this example, you will add a Remove button to each row.
<mx:DataGridColumn>
and change it to a DataGridColumn tag set by removing the “/>
” at the end of the tag and adding just the “>
” back on.<mx:DataGridColumn editable="false">
</mx:DataGridColumn>
This is the placeholder column in the DataGrid. We’ll use a start and end <mx:DataGridColumn>
tag because the item renderer definition will be placed inside it. You also do not need to specify dataField
, because there is no data you are mapping directly to.
<mx:itemRenderer>
tag set and an <fx:Component>
tag set inside the <mx:DataGridColumn>
tag.<mx:DataGridColumn editable="false">
<mx:itemRenderer>
<fx:Component>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<s:MXItemRenderer>
tag inside the <fx:Component>
tags to provide a container for the Remove button. In the MXItemRenderer specify a vertical layout with its horizontalAlign
property set to center
.When creating this inline item renderer, you want to use the vertical layout to help center the button in the DataGrid no matter the size of the cell.
<s:Button>
tag after the layout but before the end of the MXItemRenderer. Set the label
to Remove
and set the click
event to call a removeItem()
function that you will create momentarily. Pass data as ShoppingCartItem
as the parameter to the method. An import
statement for valueObjects.ShoppingCartItem
should be added automatically to the inline component. If not, add an <fx:Script>
block inside the <s:MXItemRenderer>
tag, and include the import
statement.You need to add the appropriate import
statement, because the import
statements made at the top of the file are in a scope different from the inline item renderer.
At this point there is no removeItem()
method in your renderer. When you create this method you will reuse code created in the previous lesson. In Lesson 11 you created an event subclass to hold a Product value object. Now you will reuse that event subclass to dispatch the Product object you want removed from the shopping cart.
<fx:Script>
block, which is inside the MXItemRenderer you created in the last section, create a private function named removeItem()
that returns void
and that accepts one parameter, named item
, of type ShoppingCartItem
.private function removeItem( item:ShoppingCartItem ):void {
}
removeItem()
method, declare a new local variable named prodEvent
of type ProductEvent
, and assign it a new instance of the ProductEvent event class. For the type parameter of the ProductEvent constructor, pass the event name removeProduct
. Then pass the item.product
value as the second constructor parameter. Finally, dispatch the event.If you use code-completion, events.ProductEvent
will be imported for you. If not, be sure to import it manually. This event will now be dispatched from the itemRenderer and will bubble up toward ShoppingView.
<fx:MetaData>
tag. Inside it, declare that CartGrid.mxml will dispatch an event named removeProduct
. Indicate that the event will be of type events.ProductEvent
.You are now dispatching the Product object you wish removed from the shopping cart. Of course, to actually have it removed you must handle the dispatched event, which you will now do in the next steps.
removeProduct
event that you just created in CartGrid. For the event handler call the previously created removeProductHandler()
method and pass the event object as a parameter.The extended event is handled in the CartGrid component. The removeProductHandler()
method you built in the previous lesson does the removal of the product from the cart.
You need to create a labelFunction
to display the subtotal in the third column of the DataGrid. Recall that in Lesson 10 you created a labelFunction
to display the product name in a List component. The method signature for a labelFunction
on a DataGrid is labelFunctionName(item:Object, dataField:DataGridColumn)
.
<fx:Script>
block.<fx:Script>
block, add a private function named renderPriceLabel
with the arguments item
typed as a ShoppingCartItem
and column
with the datatype DataGridColumn
. The function itself will return a String.If you use code-completion, cart.ShoppingCartItem
will be imported for you. If not, be sure to import it manually.
Because the DataGrid has multiple columns that can each have its own labelFunction
, as well as share the same labelFunction
, the second argument is used to distinguish between which DataGridColumn is using the labelFunction
. If you know that your function will be used on just one column, you can ignore the second argument in your code.
renderPriceLabel()
function, create a variable local to the function named subtotal
with the datatype Number
, and assign it the particular column’s dataField
value from the item
.var subtotal:Number = item[ column.dataField ];
If you were not creating this function for use by multiple columns, you could have assigned the variable simply as item.subtotal
. This would have assigned the correct value. But, since you want the function to be reusable, you use the column name to retrieve the correct data, hence item[ column.dataField ]
.
For now, you want to put a simple mask on the price to represent the number as a dollar figure. The signature and functionality of the labelFunction
is the same on the DataGrid as it is on the List.
<mx:DataGridColumn>
with a dataField
of subtotal
with a new attribute of labelFunction
set to renderPriceLabel
.<mx:DataGridColumn dataField="subtotal" headerText="Amount"
labelFunction="renderPriceLabel" editable="false"/>
This will have the subtotal column use renderPriceLabel
on each of the rows in the DataGrid.
The final code for the CartGrid.mxml should look like the following:
The AdvancedDataGrid expands the capabilities of the normal DataGrid. The AdvancedDataGrid control provides added features and greater control of data display, data aggregation, and data formatting. In this section not all features of the AdvancedDataGrid will be used. The less complex features are clearly explained in the Flex user documentation, so the discussion here will cover some of the more conceptually difficult capabilities.
At this point, the shopping application does not have a good-use case for the AdvancedDataGrid, so you’ll practice with some smaller files.
In the AdvancedDataGrid, you can now sort by multiple columns, whereas the DataGrid can sort only one column at a time. This behavior differs according to the Boolean value assigned to the AdvancedDataGrid’s sortExpertMode
property. When that property is set to false
, clicking the header area of a column makes that the first-priority sort. Clicking in the multiple-column sort area adds more sort criteria. The numbers at the top of the columns indicate the sorting order. If you wish to reset the top-level sort, click the header area of a column and that column becomes the first-priority sort.
You have now imported the project so you can run the applications for AdvancedDataGrid.
By clicking in the header area, you set sorting by category to be the first-priority sort, and the 1 that appears confirms this.
You see that the names are now sorted within categories and the number 2 that appears in the name column confirms this is the second-level sort.
This changes the first-priority sort to be by quantity.
By clicking in the multiple-column sort area, you toggle the sort from ascending to descending.
When you set the sortExpertMode
property to true
, sorting behaviors change, as well as component visuals. You will not see the multiple-column sort areas. To perform a multiple-column sort in this mode, first click in the column header you want for the first-priority sort. Then, Ctrl-click (or Command-click for the Mac) in the header area to add additional sort criteria. The numbers at the top of the columns indicate the sorting order. If you wish to reset the top-level sort, click (not Ctrl-click) the header area of a column, and that column becomes the first-priority sort.
sortExpertMode
property is set to true
. Run the application.Note that there are no multiple-column sort areas displayed.
Note that when you Ctrl-clicked the name column header, the names were sorted by name within the category. Also, the number 2 appeared in the column header to indicate the sorting order.
Ctrl-clicking again in a header that already has a sort applied toggles the sort from ascending to descending.
This resets the top-priority sort, in this case to the quantity field.
There are times when you will want to change the look of the AdvancedDataGrid. For instance, you may wish to draw attention to a particular row, column, or cell. A common example of this is to have negative numbers displayed in red. The AdvancedDataGrid allows you to write and apply styling functions to implement this functionality.
Your first task is to change the default look of the grid by applying a style to an entire column.
Note that there is no special styling on the grid.
myStyleFunc()
which returns an Object
. The function should accept two parameters, the first named data
, data-typed as Object, and the second named col
, data-typed as AdvancedDataGridColumn.Note that the signature of the style function must accept two parameters, the first being an Object and the second an AdvancedDataGridColumn. The first parameter represents the data for a particular row in the AdvancedDataGrid, and the second contains information about the column that the styleFunction
property is associated with.
The function must return an Object, which is usually one of two kinds of values. The first is null
, which means you do not want any styling applied. The function can also return an Object composed of one or more style properties and associated values.
color
property with the hexadecimal value 0xFF0000
, and the fontWeight
property with the string value bold
. Your style function should appear as shown here.The object returned will be used as a style sheet and applied to part of the AdvancedDataGrid.
<mx:AdvancedDataGridColumn>
tag that displays the category information, add the styleFunction
property and reference the function you just wrote, myStyleFunc.styleFunction="myStyleFunc"
This will apply the style function you just wrote to the column.
To change the style of a particular row, you also reference a function using the styleFunction
property. To change a row, use the styleFunction
property with the AdvancedDataGrid tag itself. Then add logic to the function to return the style object only when you want.
Note that there is no special styling on the grid.
styleFunction
property to the <mx:AdvancedDataGrid>
tag and have it reference the style function named myStyleFunc
.Adding the style function to the AdvancedDataGrid tag itself causes the style function to be called for every row. For this reason you will add logic to the function so not all rows have the style applied.
return
statement and add an empty if-else
statement.The if-else
statement will be used to control which row will be styled.
if-else
statement, check to see if the cost of the data in the current row is .99.if(data["cost"]==.99)
Remember that the data
parameter contains all the data of a particular row of the grid. So, the if
statement is checking to see if the cost field for a particular row is .99.
{color:0xFF0000,fontWeight:"bold"}
, and if the condition is false, return null
.This is the completed style function.
The style function could be written more concisely, but it may not be as clear. You can take advantage of the fact that an if
statement without braces ({}) will execute only the next line of code. Also, once a function returns a value, it does not continue to execute any other code. Using this information, you could rewrite the function to appear as follows:
Brevity is not always your goal when writing code, so use the approach that is clearest to you and your team.
If you wish to style cells, you still use a style function. You move the styleFunction
property back to one of the AdvancedDataGridColumn tags and add logic to return a style only when certain criteria are met. For instance, you may wish to style only the cells that contain the value .99, not the whole row as was just shown.
This contains the same code as the starting file used when styling a row.
styleFunction
property to the <mx:AdvancedDataGridColumn>
tag that displays the cost and references the myStyleFunc
function.<mx:AdvancedDataGridColumn dataField="cost" styleFunction="myStyleFunc"/>
This will apply the function only to the cost column of the grid.
Grouping data is an often-requested feature of the DataGrid and is now implemented in the AdvancedDataGrid. The grouping feature allows you to select a data field and group data by that field in a Tree control–like manner. This feature lets you create what is sometimes called a Tree DataGrid because the first column contains an expandable tree to determine which rows are visible in the grid, as shown here.
You have two approaches to implement this functionality, either through ActionScript or via tags nested in the AdvancedDataGrid tag itself. Both methods follow the same approach, which is manipulating the dataProvider of the AdvancedDataGrid.
You will first implement grouping using tags.
Notice that all the data are displayed in nongrouped rows.
dataProvider
property from the <mx:AdvancedDataGrid>
tag, and insert an <mx:dataProvider>
tag set just below the <mx:AdvancedDataGrid>
tag.Grouping is implemented by manipulating the dataProvider of the grid.
id
property of myGroup
. Bind the source
property to the dp
ArrayCollection.The GroupingCollection2 class permits you to group data. Its properties permit you to specify both the data to be grouped, as well as how it should be grouped and where it is displayed.
<mx:Grouping>
tag set inside the GroupingCollection2 block. Inside the Grouping block, use the <mx:GroupingField>
tag and set the name
property to be cat
, which specifies the field on which to group the data. The complete <mx:dataProvider>
tag block should appear as shown here.The tag that actually specifies the field to group on is <mx:GroupingField>
. The name
property specifies the field on which to group.
Notice that no grouping has taken place. In fact, the grid is now not showing any data.
creationComplete
event to the AdvancedDataGrid and specify myGroup.refresh()
to be executed.<mx:AdvancedDataGrid creationComplete="myGroup.refresh()"
height="200">
The refresh()
method of the GroupingCollection2 class actually applies the grouping to the data.
Rather than add tags to the AdvancedDataGrid as you did in the last task, this exercise will now manipulate the dataProvider using ActionScript. The manipulation will take place in a function called initDG
, whose skeleton is provided for you. You will later call the function from a creationComplete
event on the AdvancedDataGrid.
Notice that all the data is displayed in nongrouped rows.
import mx.collections.ArrayCollection;
import mx.collections.GroupingField;
import mx.collections.Grouping;
import mx.collections.GroupingCollection2;
You will be working with the same classes you did in the previous exercise when you implemented grouping with tags, so you must import them. You could have also used the classes in code and Flash Builder would have made the appropriate imports automatically.
initDG()
function, whose skeleton was provided for you, create a new GroupingCollection2 object named myGroupColl
.var myGroupColl:GroupingCollection2=new GroupingCollection2();
The GroupingCollection2 class, and its supporting classes and properties, permits you to implement grouping.
myADG
, to the source
property of the myGroupColl object.myGroupColl.source=myADG.dataProvider;
Remember that grouping is basically implemented by manipulating the dataProvider of the grid, so this statement assigns the dataProvider of the AdvancedDataGrid to a property of the GroupingCollection2 so it can be manipulated.
group
.var group:Grouping=new Grouping();
The Grouping object will act as a holder for a GroupingField object that indicates the grouping specification.
gf
. Pass as a parameter to the constructor the cat
field.var gf:GroupingField=new GroupingField("cat");
This GroupingField object specifies that the grouping will be implemented on the product category field.
fields
property of the Grouping object the GroupingField object.group.fields=[gf];
The fields
property of a Grouping object contains an array of GroupingField objects that specify the fields used to group the data. In this case, you designated the cat field as the grouping field, so this is what is assigned to the Grouping object’s fields
property.
group
, to the GroupingCollection2 object’s grouping
property.myGroupColl.grouping=group;
The creation of the grouping collection is complete, but the application will not run correctly without two more lines of code.
refresh()
method to set the grouping on the GroupingCollection2 object, and then assign the GroupingCollection2 object back to the AdvancedDataGrid’s dataProvider.myGroupColl.refresh();
myADG.dataProvider=myGroupColl;
You must refresh the GroupCollection using the refresh()
method, then assign the GroupingCollection2 object to the dataProvider of the AdvancedDataGrid before you will see any results in the application.
initDG()
function appears as shown here.You’ve built the function to implement grouping, but as of yet you have not called the function.
creationComplete
event to the <mx:AdvancedDataGrid>
tag and call the initDG()
function.The function that manipulates the dataProvider will now be called to implement grouping.
To review, here are the steps you just completed to group via ActionScript:
source
property of the GroupCollection object the AdvancedDataGrid’s dataProvider.fields
property of the Group object.grouping
property of the GroupingCollection2.Often when displaying data in a table, you want to display summaries of that data. For instance, when displaying sales data by region, you may want to display summary data for each of the regions. This is now possible with the AdvancedDataGrid. Just as with the grouping of data, you can create summary data with tags or ActionScript. Because you can display summary information for data represented only by the GroupingCollection2 class, you will work with the code you finished in the previous exercises where grouping was correctly implemented.
The basic concept of summary data is shown in the following figure:
Here the summary shows the number of bakery items purchased is five.
In this exercise, you will use the working grouping example and add summary data. You will implement summary information with tags, and in the next exercise, you will implement the same functionality using ActionScript.
<mx:AdvancedDataGridColumn dataField="summary"/>
This will add a column to contain the summary data. You will create the summary field using tags.
<mx:GroupingField name="cat">
</mx:GroupingField>
The summary tags must be nested inside the GroupingField tag block.
<mx:summaries>
tag set nested in the GroupingField block.You create summary data about your groups by using the summaries
property of the GroupingField class.
<mx:SummaryRow>
tag set nested in the summaries block. Add to the opening SummaryRow tag a summaryPlacement
property, set equal to last
.<mx:GroupingField name="cat">
<mx:summaries>
<mx:SummaryRow summaryPlacement="last">
</mx:SummaryRow>
</mx:summaries>
</mx:GroupingField>
The summaryPlacement
property specifies where the summary row appears in the AdvancedDataGrid control. Your options are:
• first:
Create a summary row as the first row in the group.
• last:
Create a summary row as the last row in the group.
• group:
Add the summary data to the row corresponding to the group.
You can also specify multiple locations by using the property values separated by a space. For instance, you could use the value last group
to have the summary in two locations, as shown here.
So, by specifying last
as the option, the summary information will be displayed after all the products in a specific category.
<mx:fields>
tag pair. In that tag set, nest an <mx:SummaryField2>
tag. In the SummaryField2 tag, set the following three properties to the indicated values:• dataField:
qty
• summaryOperation:
SUM
• label:
summary
The fields
property of the SummaryRow class holds one or more SummaryField2 objects. The SummaryField2 objects define how the summary should be created. The dataField
property defines on which data field the summary will be computed. The summaryOperation
defines how the summary data should be computed. Valid values are:
• SUM
• MIN
• MAX
• AVG
• COUNT
If those operations do not perform the calculation you need, you can use a summaryFunction
property to specify a function to compute a custom data summary.
The label
property associates the summary value to a property. In this case, the property name is summary
, which corresponds to the fourth AdvancedDataGridColumn you added at the start of this exercise.
You have displayed the summary information, but most likely not in the way in which you would choose. To display the data in a more readable format, you must use rendererProviders. Previously in this lesson, you used item renderers for the normal DataGrid and assigned them to individual columns. In the AdvancedDataGrid, you assign the renderers to the AdvancedDataGrid itself, and then specify where to use the renderers.
The first step is to build a simple renderer.
This creates the basis for the renderer you will create to display summary information.
text
property in the Label tag to be Total number of items: {data.summary}
for the property’s value. The entire component should appear as follows:You access the summary information through the data
property. Remember that the data
property contains all the data for a particular row in the grid and is automatically passed to the component by Flex.
<mx:rendererProviders>
tag set. In the rendererProviders tag set, insert an <mx:AdvancedDataGridRendererProvider>
tag. In the AdvancedDataGridRendererProvider, set the following four properties to the values indicated.• dataField
: summary
• columnIndex
: 1
• columnSpan
: 2
• renderer
: renderers.SummaryText
Your code should appear as shown here:
In this case, the rendererProviders
property contains only one definition of an AdvancedDataGridRendererProvider, but the property can contain one or more definitions. This particular renderer is tied to the summary
field, and the columnIndex
property will cause the renderer to be displayed in the first column, where columns are zero-indexed. The columnSpan
property will cause the renderer to span two columns. The renderer
property that indicates the component to use is in the renderers directory and is named SummaryText.
You could have placed this block of code anywhere in the AdvancedDataGrid tag block as long as it wasn’t nested in a tag set other than AdvancedDataGrid. For instance, the block of code could have also been placed just below the opening <mx:AdvancedDataGrid>
tag or just above the <mx:columns>
tag block.
You no longer need this column because you specified where the renderer should be displayed. Leaving in this column would cause the summary data to be displayed by both the renderer and the column.
Just as you implemented grouping with both tags and ActionScript, so you can implement summaries with both tags and ActionScript. Use as a starting file the code that implemented grouping with ActionScript, plus the AdvancedDataGridRendererProvider you created in the previous exercise.
import mx.collections.ArrayCollection;
import mx.collections.GroupingField;
import mx.collections.Grouping;
import mx.collections.GroupingCollection2;
import mx.collections.SummaryField2;
import mx.collections.SummaryRow;
You could have also just used these classes in code, and Flash Builder would have imported them for you.
initDG()
function, locate where the GroupingCollection2 object, named myGroupColl, invokes the refresh()
method. Create a few blank lines just above this code. This is where you must enter the code to create the summary information. In this location, create a SummaryRow instance named sr
and a SummaryField2 instance named sf
.var sr:SummaryRow=new SummaryRow();
var sf:SummaryField2=new SummaryField2();
Both of these objects are needed, just as you needed them when implementing summaries with tags.
sf
object the following three properties and associated values:• dataField:
qty
• summaryOperation:
SUM
• label:
summary
sf.dataField="qty";
sf.summaryOperation="SUM";
sf.label="summary";
These values are assigned for the same reasons mentioned when implementing summaries with tags.
fields
property of the SummaryRow object.sr.fields=[sf];
The fields
property of a SummaryRow object contains an array of SummaryField2 objects. These objects specify the fields used to compute summary information.
summaryPlacement
property of the SummaryRow object to the value last
.sr.summaryPlacement="last";
The values for the summaryPlacement
property are the same as discussed when implementing summaries with tags.
summaries
property of the GroupingField object, in this case named gf
, the SummaryRow object, using array notation.gf.summaries=[sr];
The summaries
property contains an array of SummaryRow instances that define the summaries to be created.
initDG()
method appears as shown here, paying special attention to the code just added to implement summary information.In this lesson, you have:
• Displayed a dataset via a DataGrid (pages 289–292)
• Defined the viewable columns of a DataGrid through DataGridColumn (pages 292–293)
• Created an MXML component to be used as an item renderer (pages 293–295)
• Created an inline custom item renderer for a DataGridColumn (pages 296–299)
• Displayed information from a DataGridColumn using a labelFunction
and an item renderer (pages 299–302)
• Learned how to raise events from inside an item (page 302)
• Sorted the AdvancedDataGrid in two different ways (pages 302–304)
• Applied custom styling to rows, columns, and cells of the AdvancedDataGrid (pages 304–309)
• Manipulated the dataProvider for an AdvancedDataGrid to group data in an AdvancedDataGrid (pages 309–314)
• Created summary information for data in an AdvancedDataGrid (pages 314–323)