Lesson 12. Using DataGrids and Item Renderers

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.

image

The shopping cart displayed in a DataGrid

Spark and MX

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.

Introducing DataGrids and Item Renderers

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.

Tip

image

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.

Displaying the ShoppingCart with 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.

  1. Locate the components package that you used in the previous exercise.

    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.

  2. Right-click the components package and choose New > MXML Component. In the dialog box, specify the Name to be CartGrid.
  3. For the “Based on” value, click the Browse button. In the dialog box, begin to type DataGrid until you see DataGrid – mx.controls displayed. Choose the DataGrid entry. Click OK, then Finish.
  4. In the newly created component’s <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">

  5. After the <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.

  6. In the <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.

  7. Define an <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.

  8. Define an <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" />

  9. Define an <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.

  10. At this point, your component should appear as shown here:

    image

  11. Save CartGrid.mxml.

Using the CartGrid Component

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.

  1. Open ShoppingView.mxml from the views package.
  2. Locate the <mx:DataGrid> block near the bottom of the file and remove it.
  3. In the same location add the <components:CartGrid> component. Set the id to dgCart, the includeIn to cartView, and the width and height to 100%.
  4. In the CartGrid, bind the dataProvider to shoppingCart.items.

    <components:CartGrid id="dgCart"
         includeIn="cartView"
         width="100%" height="100%"
         dataProvider="{shoppingCart.items}" />

  5. Run the FlexGrocer.mxml. Add products to the shopping cart, and then click the View Cart button.

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:

image

Adding Inline Editing Control for DataGridColumn

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):

image

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.

Tip

image

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.

  1. Open the CartGrid.mxml file that you created in a previous exercise.
  2. In the <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.

  3. Save CartGrid.mxml. Run the FlexGrocer application, add the Buffalo product to the shopping cart, and click View Cart.

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.

image

Creating an Item Renderer for Displaying the Product

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.

  1. Right-click the components package and choose New > MXML Component. In the New MXML Component dialog box, set the Name to ProductName, the Layout to HorizontalLayout, the base component to an MXItemRenderer; remove any width and height values; and then click Finish.

    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.

  2. In the <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.

  3. Place an <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"/>

    Tip

    image

    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.

  4. Place an <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%"/>

  5. Save the ProductName.mxml file.

    You cannot test this component at this time because it is not yet assigned to the DataGrid.

  6. Open the CartGrid.mxml you created in the previous exercise.
  7. Update the <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.

  8. Update the <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.

    Tip

    image

    This attribute can be used to allow for exploding details inside a DataGrid row. In this case, you can have summary data in a cell that expands to show details if you click an icon or button.

  9. Save CartGrid.mxml. Run the FlexGrocer application, add the Buffalo product to the shopping cart, and click View Cart.

    image

Creating an Inline MXML Item Renderer for Displaying a Remove Button

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.

Tip

image

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.

  1. Open the CartGrid.mxml you created in the previous exercise.
  2. Locate the fourth <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.

  3. Place an <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>

  4. Place an <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.

    image

    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.

  5. Place an <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.

    image

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.

Reusing the ProductEvent Class

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.

  1. Inside the <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 {
    }

  2. Inside the 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.

    image

    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.

  3. Outside the MXItemRenderer, just after the opening DataGrid tag, add an <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.

    image

    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.

  4. Save the file.
  5. Open ShoppingView.mxml. Locate the instantiation of CartGrid you coded earlier in this lesson.
  6. Place your cursor in the tag and press Ctrl-Spacebar to bring up code completion. Select the 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.

    image

    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.

  7. Run FlexGrocer and add items to the cart. Click the View Cart button and confirm you can remove items from the cart using the Remove button.

Create a labelFunction to Display the Subtotal

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).

  1. In CartGrid.mxml, create a new <fx:Script> block.
  2. Inside the <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.

    image

    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.

  3. As the first line of code in the 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 ].

  4. As the last line of code in the function, return the subtotal of the item formatted with a $.

    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.

    image

  5. Update the <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.

  6. Check the code for the component you have built.

    The final code for the CartGrid.mxml should look like the following:

    image

    image

  7. Save CartGrid.mxml. Run the FlexGrocer.mxml application, add the Buffalo product to the shopping cart, and click View Cart. Notice both the formatting on the Amount column and the Remove button in the shopping cart.

    image

Using the AdvancedDataGrid

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.

Sorting the AdvancedDataGrid

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.

image

  1. Import the ADGStart.fxp project from the Lesson12/independent folder into Flash Builder. Please refer to Appendix A for complete instructions on importing a project.

    You have now imported the project so you can run the applications for AdvancedDataGrid.

  2. Run the SortingADG.mxml application.
  3. Click the cat header area to sort by product category, and note that the number 1 appears in the multiple-column sort area.

    By clicking in the header area, you set sorting by category to be the first-priority sort, and the 1 that appears confirms this.

  4. Now click in the multiple-column sort area for the name column to make it the secondary sort.

    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.

  5. Click in the qty header area.

    This changes the first-priority sort to be by quantity.

  6. Click in the multiple-column sort area for the qty header. Note that the direction of the arrow in the area changes.

    By clicking in the multiple-column sort area, you toggle the sort from ascending to descending.

  7. Close the browser, return to Flash Builder, and close the SortingADG.mxml file.

Sorting in Expert Mode

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.

image

  1. Open the application SortingExpertADG.mxml and note the sortExpertMode property is set to true. Run the application.

    Note that there are no multiple-column sort areas displayed.

  2. Click the cat column header to sort the AdvancedDataGrid by product category. Now, Ctrl-click (Command-click) the name column header.

    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.

  3. Ctrl-click again in the name header area.

    Ctrl-clicking again in a header that already has a sort applied toggles the sort from ascending to descending.

  4. Click in the qty column header.

    This resets the top-priority sort, in this case to the quantity field.

  5. Close the browser, return to Flash Builder, and close the SortingExpertADG.mxml file.

Styling the AdvancedDataGrid

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.

Styling columns

Your first task is to change the default look of the grid by applying a style to an entire column.

  1. Open the application StyleColumnADG.mxml and run it.

    Note that there is no special styling on the grid.

  2. At the bottom of the Script block, create a new public function named 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.

  3. In the body of the function, return an Object associating the color property with the hexadecimal value 0xFF0000, and the fontWeight property with the string value bold. Your style function should appear as shown here.

    image

    The object returned will be used as a style sheet and applied to part of the AdvancedDataGrid.

  4. In the <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.

  5. Run the application and note that the category column has red and bold text in it.

    image

  6. Close the StyleColumnADG.mxml file.

Styling rows

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.

  1. Open the application StyleRowADG.mxml. Note that the signature for the style function is included and returns null, so no error is reported. Run the application.

    Note that there is no special styling on the grid.

  2. Add the styleFunction property to the <mx:AdvancedDataGrid> tag and have it reference the style function named myStyleFunc.

    image

    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.

  3. In the style function, remove the return statement and add an empty if-else statement.

    image

    The if-else statement will be used to control which row will be styled.

  4. For the condition of the 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.

  5. If the condition is true, return the styling object {color:0xFF0000,fontWeight:"bold"}, and if the condition is false, return null.

    image

    This is the completed style function.

  6. Run the application and note the two rows with a cost of .99 are styled.

    image

    Note

    image

    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:

    image

    Brevity is not always your goal when writing code, so use the approach that is clearest to you and your team.

  7. Close the StyleRowADG.mxml file.

Styling cells

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.

  1. Open the StyleCellADG.mxml file.

    This contains the same code as the starting file used when styling a row.

  2. Implement the same logic in the style function as you did in the last exercise.

    image

  3. Add a 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.

  4. Run the application and note only the cells containing .99 are styled.

    image

  5. Close the StyleCellADG.mxml file.

Grouping Data

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.

image

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.

Grouping data with tags

You will first implement grouping using tags.

  1. Open the application GroupWithTagsADG.mxml and run it. Note that the category column has been removed, because this is the column you will be grouping on.

    Notice that all the data are displayed in nongrouped rows.

  2. Remove the dataProvider property from the <mx:AdvancedDataGrid> tag, and insert an <mx:dataProvider> tag set just below the <mx:AdvancedDataGrid> tag.

    image

    Grouping is implemented by manipulating the dataProvider of the grid.

  3. In the dataProvider tag set, nest a GroupingCollection2 tag set, and specify an id property of myGroup. Bind the source property to the dp ArrayCollection.

    image

    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.

  4. Nest an <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.

    image

    The tag that actually specifies the field to group on is <mx:GroupingField>. The name property specifies the field on which to group.

  5. Run the application.

    Notice that no grouping has taken place. In fact, the grid is now not showing any data.

  6. Add a 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.

  7. Run the application again, and you will see the data grouped on the category field.

    image

  8. Close the GroupWithTagsADG.mxml file.

Grouping data with ActionScript

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.

  1. Open the application GroupWithActionScriptADG.mxml and run it. Note that the category column has been removed, because this is the column you will be grouping on.

    Notice that all the data is displayed in nongrouped rows.

  2. In the Script block, following the import of the ArrayCollection class, import the classes you used in the last exercise via tags: the GroupingField, Grouping, and GroupingCollection2 classes.

    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.

  3. Inside the 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.

  4. Now assign the dataProvider of the AdvancedDataGrid, whose instance name is 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.

  5. Next, create a new Grouping object named group.

    var group:Grouping=new Grouping();

    The Grouping object will act as a holder for a GroupingField object that indicates the grouping specification.

  6. Define the field on which to group by creating a new GroupingField object named 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.

  7. Now, using array notation, assign the 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.

  8. To complete the creation of the grouping, assign the Grouping object, in this case 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.

  9. As the last two lines of the function, use the 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.

  10. Be sure your initDG() function appears as shown here.

    image

    You’ve built the function to implement grouping, but as of yet you have not called the function.

  11. Add a creationComplete event to the <mx:AdvancedDataGrid> tag and call the initDG() function.

    image

    The function that manipulates the dataProvider will now be called to implement grouping.

  12. Run the application and confirm that grouping on the product categories is working just as it did when implemented in the previous exercise with tags.

    image

  13. Close the GroupWithActionScriptADG.mxml file.

    To review, here are the steps you just completed to group via ActionScript:

    1. Create a GroupCollection object.
    2. Assign to the source property of the GroupCollection object the AdvancedDataGrid’s dataProvider.
    3. Create a new Grouping object.
    4. Create a new GroupingField object that specifies the field on which to group.
    5. Assign an array of GroupingField objects to the fields property of the Group object.
    6. Assign the Grouping object to the grouping property of the GroupingCollection2.
    7. Refresh the GroupingCollection2.
    8. Assign the GroupingCollection2 to the dataProvider of the AdvancedDataGrid.

Displaying Summary Data

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:

image

Here the summary shows the number of bakery items purchased is five.

Displaying summary data with tags

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.

  1. Open the application SummaryWithTagsADG.mxml and run it. You see that grouping is functioning on the category field.
  2. Add a fourth AdvancedDataGridColumn to display a field called summary, which you will create shortly.

    <mx:AdvancedDataGridColumn dataField="summary"/>

    This will add a column to contain the summary data. You will create the summary field using tags.

  3. Change the GroupingField tag into a tag set with opening and closing tags.

    <mx:GroupingField name="cat">

    </mx:GroupingField>

    The summary tags must be nested inside the GroupingField tag block.

  4. Insert an <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.

  5. Insert an <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.

    image

    last: Create a summary row as the last row in the group.

    image

    group: Add the summary data to the row corresponding to the group.

    image

    Tip

    image

    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.

    image

    So, by specifying last as the option, the summary information will be displayed after all the products in a specific category.

  6. In the SummaryRow block, nest an <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

    image

    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

    Tip

    image

    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.

  7. Check to be sure your AdvancedDataGrid appears as shown here:

    image

  8. Run the application. You will see that summary data is displaying as the last line of the category group. The sum of the quantities in that group is the summary information displayed.

    image

  9. Do not close the file at this time.

Changing the display using rendererProviders

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.

  1. Right-click the renderers package and then choose New > MXML Item Renderer. Enter renderers as the Package and SummaryText as the Name, and use the Item renderer for XM AdvancedDataGrid for the template. Click Finish.

    This creates the basis for the renderer you will create to display summary information.

  2. Alter the 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:

    image

    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.

  3. Return to the SummaryWithTagsADG.mxml file and just above the closing AdvancedDataGrid tag, insert an <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:

    image

    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.

    Tip

    image

    When the columnSpan property is set to 0, the renderer spans all columns in the row.

    Note

    image

    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.

  4. Remove the column that displays the summary.

    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.

  5. Run the application to see the renderer in action.

    image

    Tip

    image

    If you do not like the document icon in front of each product, you can bind the defaultLeafIcon to null to remove it.

    <mx:AdvancedDataGrid creationComplete="myGroup.refresh()"   defaultLeafIcon="{null}">

    image

  6. Close the SummaryWithTagsADG.mxml file.

Displaying summary data with ActionScript

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.

  1. Open the SummaryWithActionScriptADG.mxml application.
  2. In the Script block following the import of the ArrayCollection class and the grouping classes, import the SummaryField2 and SummaryRow classes you used in the last section via tags.

    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.

  3. Inside the 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.

  4. Now, assign the 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.

  5. Using array notation, assign the SummaryField2 object to the 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.

  6. Set the 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.

  7. As the last line of code needed to create a summary, assign the 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.

  8. Check to be sure your initDG() method appears as shown here, paying special attention to the code just added to implement summary information.

    image

  9. Run the application, and you will see the summary information just as it appeared when using tags.

    image

  10. Close the SummaryWithActionScriptADG.mxml file.

What You Have Learned

In this lesson, you have:

• Displayed a dataset via a DataGrid (pages 289292)

• Defined the viewable columns of a DataGrid through DataGridColumn (pages 292293)

• Created an MXML component to be used as an item renderer (pages 293295)

• Created an inline custom item renderer for a DataGridColumn (pages 296299)

Displayed information from a DataGridColumn using a labelFunction and an item renderer (pages 299302)

• Learned how to raise events from inside an item (page 302)

• Sorted the AdvancedDataGrid in two different ways (pages 302304)

• Applied custom styling to rows, columns, and cells of the AdvancedDataGrid (pages 304309)

• Manipulated the dataProvider for an AdvancedDataGrid to group data in an AdvancedDataGrid (pages 309314)

• Created summary information for data in an AdvancedDataGrid (pages 314323)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset