3 August 2009
All
Welcome to Part 4 of this tutorial series. In this part, you will make the code more flexible by creating reusable custom components. Figure 1 shows you the wagon assembly line that you laid out in Part 2 and added data to in Part 3. In this tutorial, you will transfer existing code for the colored bins and clock from the main application to custom component files. You will also create additional code to handle the bin color change and implement getter and setter functions for class properties.
Note: Parts 1 through 6 focus on teaching Flex development to SAP developers. Part 7 teaches Flex developers how to create a Web Dynpro application. Parts 8 and 9 show both SAP and Flex developers how to integrate the Flex application as a Rich Island into the Web Dynpro application.
Figure 2 outlines the Flex framework controls and containers that you will use in this application. Note that containers (such as Application, VBox, or Canvas containers) hold other containers or controls and are used to lay out visual elements in an application. In this tutorial you create a reusable custom component by transferring the VBox code layout, relevant variables, and functions from the main application.
You used the following variables in previous tutorials:
_wagonInventory: The inventory data that populates the colored bins._wagonYellowWarningAmount: The minimum number of wagons that can be created, based on the available inventory, when a bin turns yellow._inventoryNeededForYellow: The number of parts needed in a bin to make the wagons for the _wagonYellowWarningAmount._wagonRedWarningAmount: The minimum number of wagons that can be created, based on available inventory, when you want the bin to turn red and the assembly line to stop._inventoryNeededForRed: The number of parts needed in the bin to make the wagons for the _wagonRedWarningAmount.This tutorial introduces the following variable:
_binPosition: The index of the data in the _wagonInventory ArrayCollection that populates the bin.In this section, you will create a reusable custom component file for the bins and transfer code from the main application to the new component.
The component is based on the VBox.
width and height properties.<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx=http://www.adobe.com/2006/mxml>
<mx:Script>
<![CDATA[
]]>
</mx:Script>
</mx:VBox>
binTitle0 Label control and the binCanvas0 Canvas container and its contents from the first VBox bin container and paste it into BinComponent.mxml after the closing Script tag.. . .
<mx:Label id="binTitle0"
text="{_wagonInventory.getItemAt(0).Title}"
textAlign="center"
width="100"
styleName="titleFont"/>
<mx:Canvas id="binCanvas0"
width="100" height="100"
styleName="binStyle">
<mx:TextInput id="binData0"
text="{_wagonInventory.getItemAt(0).Quantity}"
editable="false"
width="60"
height="30"
textAlign="center"
horizontalCenter="0"
verticalCenter="0"
styleName="titleFont"
fontSize="18"/>
</mx:Canvas>
binTitle0 text property value.binData0 text property value.binTitle0 to binTitle.binCanvas0 to binCanvas.binData0 to binData.Your application should appear as shown in Figure 3.
MXML custom components are equivalent to ActionScript class files. You define all of the class properties and functions in the MXML custom component code and then create instances of the component with specific properties for each instance. In this section, you use the custom component in the main application to display the bins.
components.*.Note: This code allows you to access all custom components in the components directory through the user-defined comp namespace. Remember that the pre-built Flex framework components are referenced from the mx namespace.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
backgroundGradientColors="[0xFFFFFF, 0xFFFFFF]"
initialize="startProduction()"
xmlns:comp="components.*">
clockBase Canvas container tag, add five BinComponent tags from the comp namespace and add the following properties and values to each:<comp:BinComponent x="47" y="178"/>
<comp:BinComponent x="186" y="178"/>
<comp:BinComponent x="331" y="178"/>
<comp:BinComponent x="471" y="178"/>
<comp:BinComponent x="614" y="178"/>
The application should appear as shown in Figure 4. The bin quantities are not displayed.
You send the custom component the very same data used in the main application, except for the binPosition property value, by assigning the values to the properties. The class properties are created within the custom component in the next section.
wagonRedWarningAmount and the _wagonYellowWarningAmount variables and make them bindable.[Bindable]
private var _wagonYellowWarningAmount:uint = 50;
[Bindable]
private var _wagonRedWarningAmount:uint = 0;
BinComponent component:<comp:BinComponent binPosition="0"
wagonInventory="{_wagonInventory}"
wagonRedWarningAmount="{_wagonRedWarningAmount}"
wagonYellowWarningAmount="{_wagonYellowWarningAmount}"
x="47" y="178"/>
<comp:BinComponent binPosition="1"
wagonInventory="{_wagonInventory}"
wagonRedWarningAmount="{_wagonRedWarningAmount}"
wagonYellowWarningAmount="{_wagonYellowWarningAmount}"
x="186" y="178"/>
<comp:BinComponent binPosition="2"
wagonInventory="{_wagonInventory}"
wagonRedWarningAmount="{_wagonRedWarningAmount}"
wagonYellowWarningAmount="{_wagonYellowWarningAmount}"
x="331" y="178"/>
<comp:BinComponent binPosition="3"
wagonInventory="{_wagonInventory}"
wagonRedWarningAmount="{_wagonRedWarningAmount}"
wagonYellowWarningAmount="{_wagonYellowWarningAmount}"
x="471" y="178"/>
<comp:BinComponent binPosition="4"
wagonInventory="{_wagonInventory}"
wagonRedWarningAmount="{_wagonRedWarningAmount}"
wagonYellowWarningAmount="{_wagonYellowWarningAmount}"
x="614" y="178"/>
In this section, you use accessor methods (setters and getters) to isolate class properties from direct public access and to dispatch an event when the variable data changes. By convention, you will create private variables for use in the class that are named with a preceding underscore. In the accessor methods you will assign the public variables to these private class properties so that you can explicitly control their usage within the class.
import statement, import the CollectionEvent class from the mx.events package. <mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
]]>
</mx:Script>
import statements, using the set keyword, create a public function named wagonInventory(), that takes one argument named _wagonInventory with a data type of the ArrayCollection class. The return type is void._wagonInventory to this._wagonInventory.The public argument _wagonInventory is assigned to the private variable _wagonInventory of this application.
public function set wagonInventory(_wagonInventory:ArrayCollection):void
{
this._wagonInventory = _wagonInventory;
}
setter function, using the get keyword create a public function named _wagonInventory() that takes no arguments and has a return type of the ArrayCollection class._wagonInventory.public function get wagonInventory():ArrayCollection
{
return _wagonInventory;
}
set keyword create a public function named wagonYellowWarningAmount(), that takes one argument named _wagonYellowWarningAmount with a data type of the uint class. The return type is void._wagonYellowWarningAmount to this._wagonYellowWarningAmount.public function set
wagonYellowWarningAmount(_wagonYellowWarningAmount:uint):void
{
this._wagonYellowWarningAmount = _wagonYellowWarningAmount;
}
setter function, using the get keyword create a public function named _wagonYellowWarningAmount() that takes no arguments and has a return type of the uint class._wagonYellowWarningAmount.public function get wagonYellowWarningAmount():uint
{
return _wagonYellowWarningAmount;
}
set keyword create a public function named wagonRedWarningAmount(), that takes one argument named _wagonRedWarningAmount with a data type of the uint class. The return type is void._wagonRedWarningAmount to this._wagonRedWarningAmount.public function set
wagonRedWarningAmount(_wagonRedWarningAmount:uint):void
{
this._wagonRedWarningAmount = _wagonRedWarningAmount;
}
setter function, using the get keyword create a public function named _wagonRedWarningAmount() that takes no arguments and has a return type of the uint class.return _wagonRedWarningAmount.public function get wagonRedWarningAmount():uint
{
return _wagonRedWarningAmount;
}
set keyword create a public function named binPosition(), that takes one argument named _binPosition with a data type of the uint class. The return type is void._binPosition to this._ binPosition.The _binPosition represents the index of the data in the ArrayCollection that populates the DataGrid control.public function set binPosition(_binPosition:uint):void
{
this._binPosition = _binPosition;
}
get keyword, create a public function named _binPosition() that takes no arguments and has a return type of the uint class._binPosition.public function get binPosition():uint
{
return _binPosition;
}
In this section, you will transfer all the relevant ActionScript from the main application to the custom component Script block.
Script block.Script block tags after the import statements. <mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
[Bindable] private var _wagonInventory:ArrayCollection;
[Bindable] private var _wagonYellowWarningAmount:uint = 50;
[Bindable] private var _wagonRedWarningAmount:uint = 0;
private var _inventoryNeededForYellow:uint;
private var _inventoryNeededForRed:uint;
. . .
]]>
</mx:Script>
Bindable._wagonInventory as an ArrayCollection class._wagonYellowWarningAmount variable.You passed this value in as a property of each component instance.
_wagonRedWarningAmount variable.You passed this value in as a property of each component instance.
[Bindable]
private var _wagonInventory:ArrayCollection = new ArrayCollection();
[Bindable]
private var _wagonYellowWarningAmount:uint;
[Bindable]
private var _wagonRedWarningAmount:uint;
[Bindable]
private var _inventoryNeededForYellow:uint;
[Bindable]
private var _inventoryNeededForRed:uint;
private variable named _binPosition with a data type of uint that is bound.This variable represents the index of the data in the ArrayCollection.
[Bindable]
private var _binPosition:uint;
_inventoryNeededForYellow and _inventoryNeededForRed variables.In this section you display the _wagonInventory data in the Label and TextInput controls.
binTitle Label control.Title value by passing _binPosition to the getItemAt() method of the _wagonInventory ArrayCollection, and bind it to the text property of binTitle.<mx:Label id="binTitle"
text="{_wagonInventory.getItemAt(_binPosition).Title}"
textAlign="center"
width="100"
styleName="titleFont"/>
binData TextInput control.Quantity value by passing _binPosition to the getItemAt() method of the _wagonInventory ArrayCollection, and bind it to the text property.<mx:TextInput id="binData"
text="{_wagonInventory.getItemAt(_binPosition).Quantity}"
editable="false"
width="60"
height="30"
textAlign="center"
horizontalCenter="0"
verticalCenter="0"
styleName="titleFont"
fontSize="18"/>
In this section, you will create and modify functions that allow the bin to change color if it is within the threshold when the user makes a change to the value in the DataGrid control.
binColorHandler() function.binColorHandler() function into the Script block after the variables.for loop in the function.Note: You will not need to loop over the _wagonInventory ArrayCollection because the binColorHandler() function is now specific to each instance of the colored bins. That means that the function only needs to determine the bin color for one specific bin at a time.
. . .
private function binColorHandler(event:CollectionEvent = null):void
{
_inventoryNeededForYellow = _wagonYellowWarningAmount *
_wagonInventory.getItemAt(x).Parts;
_inventoryNeededForRed = _wagonRedWarningAmount *
_wagonInventory.getItemAt(x).Parts;
if (_wagonInventory.getItemAt(x).Quantity <= _inventoryNeededForRed ||
_wagonInventory.getItemAt(x).Quantity < _wagonInventory.getItemAt(x).Parts)
{
this["binCanvas"+x].setStyle("backgroundColor", 0xCC0000);
}
else if (_wagonInventory.getItemAt(x).Quantity >
_inventoryNeededForRed &&
_wagonInventory.getItemAt(x).Quantity <= _inventoryNeededForYellow)
{
this["binCanvas"+x].setStyle("backgroundColor", 0xE5E006);
}
else
{
this["binCanvas"+x].setStyle("backgroundColor", 0x339933);
}
}
binColorHandler() function.startProduction() function and delete the _wagonInventory event listener code.The listener event code had a reference to the binColorHandler() function which you just removed from the main application and moved to the custom bin component.
In this section, you modify the reusable custom component to accept unique properties for each instance.
binColorHandler() function.this["binCanvas"+x] to binCanvas in three places.Note: You are no longer looping over the entire ArrayCollection and therefore do not need to use the dynamic instance name.
if (_wagonInventory.getItemAt(x).Quantity <=
_inventoryNeededForRed ||
_wagonInventory.getItemAt(x).Quantity <
_wagonInventory.getItemAt(x).Parts)
{
binCanvas.setStyle("backgroundColor", 0xCC0000);
}
else if (_wagonInventory.getItemAt(x).Quantity >
_inventoryNeededForRed &&
_wagonInventory.getItemAt(x).Quantity <=
_inventoryNeededForYellow)
{
binCanvas.setStyle("backgroundColor", 0xE5E006);
}
else
{
binCanvas.setStyle("backgroundColor", 0x339933);
}
In this section, you add an event listener and use the _binPosition index to retrieve data from the _wagonInventory ArrayCollection.
init() that takes no arguments and has a return type of void.addEventListener() function of _wagonInventory to listen for the CollectionEvent.COLLECTION_CHANGE event which will be handled by the binColorHandler() function.Note: Since you defined the _wagonInventory ArrayCollection instance as a bindable variable, any changes to the data will automatically be reflected everywhere it is used. However, if you want additional functions to run when the data changes, you need to add the COLLECTION_CHANGE event handler. In this case, you are adding the binColorHandler() function as the event handler when the wagon inventory data changes. This function determines the current bin color.
private function init():void
{
_wagonInventory.addEventListener
(CollectionEvent.COLLECTION_CHANGE,
binColorHandler);
}
creationComplete property with the value of init().<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init()">
This code ensures that the event listener is added when the custom component is created.
calculateQuantity() that takes no arguments and has a return type of void.You are making a reusable function that is called within other functions.
binColorHandler() function and move the _wagonYellowWarningAmount and _inventoryNeededForRed code to the calculateQuantity() function.getItemAt() function from x to _binPosition.private function calculateQuantity():void
{
_inventoryNeededForYellow = _wagonYellowWarningAmount *
_wagonInventory.getItemAt(_binPosition).Parts;
_inventoryNeededForRed = _wagonRedWarningAmount *
_wagonInventory.getItemAt(_binPosition).Parts;
}
binColorHandler() function.calculateQuantity() function.private function binColorHandler(event:CollectionEvent =
null):void
{
calculateQuantity();
. . .
The values from the calculateQuantity() function are needed for the conditional statements.
binColorHandler() function, change the value in the getItemAt() function from x to _binPosition in five places. Note: You are no longer using a for loop and will use the _binPosition value which will identify the index of the bin from the _wagonInventory ArrayCollection that you want evaluated.
. . .
if (_wagonInventory.getItemAt(_binPosition).Quantity <=
_inventoryNeededForRed ||
_wagonInventory.getItemAt(_binPosition).Quantity <
_wagonInventory.getItemAt(_binPosition).Parts)
{
binCanvas.setStyle("backgroundColor", 0xCC0000);
}
else if (_wagonInventory.getItemAt(_binPosition).Quantity >
_inventoryNeededForRed &&
_wagonInventory.getItemAt(_binPosition).Quantity <=
_inventoryNeededForYellow)
{
binCanvas.setStyle("backgroundColor", 0xE5E006);
}
else
{
binCanvas.setStyle("backgroundColor", 0x339933);
}
Change the quantity of any of the bins to 5 and press Enter. Change the quantity of any of the bins to 0 and press Enter. You should see the bin color change and the application is working as it did in Part 3.
In this tutorial, you transferred code from the main application into a reusable custom component that replaced the hard-coded colored bins. You also learned how to create setters and getters for class properties and how to create methods for the class file.
If you are interested in learning more about the topics in this tutorial, refer to the following resources:
In Part 5, you will create another custom component for the clock display and animate the clock using the ActionScript Timer class.
For your reference, here are all the parts in this series: