Here is where the excitement begins! Now you will develop the ServiceOrder class. You will gain experience working with the Flash MX 2004 Remoting ActionScript 2.0 API.
To create the ServiceOrder.as AS 2.0 class:
Import the appropriate classes necessary for your new class. In the script window, add the following code:
import mx.controls.TextInput; import mx.controls.List; import mx.controls.ComboBox; import mx.controls.Button;
To reference a class in another script, you must prefix the class name with the class's package path. This simplifies the syntax required when you create instances of the UI components in your ServiceOrder class.
// Represents a reference to a specific remote service and the methods that the service exposes import mx.remoting.Service; // Generated on each call to a Service object import mx.remoting.PendingCall; // Accesses and manipulate RecordSet objects returned by a service import mx.remoting.RecordSet; // Binds RecordSet objects to Flash components, such as ListBox or ComboBox, that have labels with associated data import mx.remoting.DataGlue;
// A responder object that relays result and fault calls to corresponding functions on the specified object import mx.rpc.RelayResponder; // Handle results from server import mx.rpc.ResultEvent; // To handle the error in your Flash application, you create a fault handler import mx.rpc.FaultEvent;
Your code should look something like this (remember, comments are optional):
import mx.controls.TextInput; import mx.controls.List; import mx.controls.ComboBox; import mx.controls.Button; import mx.remoting.Service; import mx.remoting.PendingCall; import mx.remoting.RecordSet; import mx.remoting.DataGlue; import mx.rpc.RelayResponder; import mx.rpc.FaultEvent; import mx.rpc.ResultEvent;
Add the class definition as follows:
class com.trioMotor.ServiceOrders {
private var cfConnection:NetConnection;
private var workOrders:RecordSet;
// UI Components Instances
private var serviceOrders:List;
private var statusComboBox:ComboBox;
private var submit:Button;
private var license:TextInput;
private var path:String;
/* Add constructor code will go here for the Step #7 or next step */
}
You have now created the class definition. Important: Insert the code in the remaining steps above the closing curly brace in step five.
Add the constructor for the ServiceOrders class. You pass in the connection string for your Flash Remoting Gateway from the FLA, as well as the component instance names from your view. You will also keep your constructor function uncluttered by adding an init() function.
/* Constructor example only:
var myServiceOrder:ServiceOrders = new ServiceOrders( path, statusCodes, servOrdersList, license_txt, submit);
*/
function ServiceOrders(p:String, cb:ComboBox, lb:List, txt:TextInput, btn:Button)
{
license = txt;
statusComboBox = cb;
serviceOrders = lb;
submit = btn;
path = p;
init();
}
The init() function adds listeners for the UI components.
public function init():Void
{
/* listener for the TextInput*/
license.addEventListener("change", this);
/* listener for the ComboBox*/
statusComboBox.addEventListener("change", this);
/* listener for the Button*/
submit.addEventListener("openServiceManager", this);
createConnection();
}
Define your service to the ColdFusion components. There is a Service object and Pending object, both of which are new to Flash Remoting. The documentation and syntax are provided below:
new Service (gatewayURI: String, logger:Log, serviceName:String, conn:Connection, resp:Responder)
| Parameter | Description |
|---|---|
gatewayURI |
A string specifying the gateway that should be created or used from the current pool |
logger |
A string specifying the log to which debugging messages are sent |
serviceName |
A string specifying the name of the service on which to invoke the method |
conn |
The Connection object with which this service should be associated |
resp |
A Responder object that handles the callbacks for the method calls that have been made |
Each call to a Service object generates a PendingCall object. The PendingCall object is responsible for setting up the responder and managing the result and fault outcomes.
| Property | Access | Description |
|---|---|---|
| responder | read/write | Sets or returns a Responder object |
The following example sets the PendingCall responder property with the Responder object to use (this), the name of the result handler function (onCategoryData), and the name of the fault handler function (onCategoryFault).
custService = new Service("http://localhost/flashservices/", null, "customerData", null, null);
// load category combo
var pc:PendingCall = custService.getCategories(); // get all categories
pc.responder = new RelayResponder(this, "onCategoryData", "onCategoryFault");
Add the following code after the closing bracket for public function init():Void function you added in step 8.
public function createConnection():Void
{
// Create a new Service instance. Set the gateway path property & the workOrder CFC location parameters.
var work_Orders = new Service(path, null, "mx2004tutorial.services.workOrder", null, null );
// In the CFC, call the getWorkOrders() method, which is returned to a new instance pendingWorkOrders.
// This method creates query object in ColdFusion and returns it to Flash as an Array of Objects.
var pendingWorkOrders:PendingCall = work_Orders.getWorkOrders();
// Set the responder property to the filterWorkOrder result handler & the reportError error handler.
pendingWorkOrders.responder = new RelayResponder( this, "filterWorkOrders", "reportError" );
// Create a new Service instance. Set the gateway path property & the statusCode CFC location parameters.
var status_Code = new Service(path, null, "mx2004tutorial.services.statusCode", null, null );
// Invoke the getStatusCodes() and return pendingstatusCode instance.
var pendingstatusCode:PendingCall = status_Code.getStatusCodes();
// Set the responder property to the fillComboBox result handler & reuse the reportError error handler.
pendingstatusCode.responder = new RelayResponder( this, "fillComboBox", "reportError" );
}
When the recordset has been received, the RelayResponder calls the fillComboBox method. You named the object r, which is a ResultEvent data type. The DataGlue class lets you bind recordsets to a component.
public function fillComboBox(r:ResultEvent):Void
{
/* Populate the ComboBox with the returned recordSet using DataGlue.bindFormatString to remap
fields so that label equals STATUS_NAME field and data equals STATUS_ID field. A ColdFusion programmer
will be familiar with the #variable# syntax.
example: DataGlue.bindFormatStrings( component, object, label, data );
*/
DataGlue.bindFormatStrings( statusComboBox, r.result, "#STATUS_NAME#", "#STATUS_ID#" );
}
Define a simple error-handling method using a trace statement that displays the error message. This is helpful during the debugging process. In the responder, you defined the reportError fault handler function, which is called if there is a problem.
public function reportError(myFault:FaultEvent):Void
{
trace("reportError: " + myFault.fault.faultstring);
}
This function returns a Boolean if the record needs to be filtered based on user input from the components.
public static function FILTER_FUNCTION(record, obj ):Boolean
{
/* Make the license text the same length of the obj.text length to compare them. */
var licenseText:String = record.LICENSE.substr( 0, obj.txt.length );
/* Return true if both texts and ids are equal or if texts are equal and id is "All
* Active" (id = 1). Otherwise returns false. */
return (licenseText == obj.txt && ( record.STATUS_ID == obj.id || obj.id == 1) )
}
This function populates the ListBox component with the service orders.
public function filterWorkOrders(r:ResultEvent):Void
{
/* Keep a reference to the query returned casting to a recordset class*/
if(r != undefined) workOrders = RecordSet(r.result);
/* Clean your List, removing all current items. */
serviceOrders.removeAll();
/* This object will be passed to the filter function with two properties. */
var filterParams:Object = {};
/* Get the text typed in the TextInput and convert it to upper case. */
filterParams.txt = license.text.toUpperCase();
/* Get the selected item from the ComboBox.
* If this is undefined we assign the value 1, which corresponds to the ID of "All
* Active".
*/
filterParams.id = (statusComboBox.selectedItem.data != undefined) ? statusComboBox.selectedItem.data : 1;
/* Apply the filter that returns a new RecordSet. */
var rec:RecordSet = workOrders.filter(FILTER_FUNCTION, filterParams);
/* Get the Iterator from this new filtered recordset and populate the List. */
var it = rec.getIterator();
while( it.hasNext())
{
var record = it.next();
serviceOrders.addItem(record.LICENSE + " ( " +record.STATUS_NAME + " )", record.WORK_ORDER_ID );
}
}
Whenever a user makes a selection in the ComboBox or updates the TextInput component, the application calls this method. You have registered a listener of these two components.
public function change():Void
{
filterWorkOrders();
}
If the user clicks the submit button, the application calls this method. The user will be sent to the Service Manager application and the code preserves the state from the component and maintains the state of components using URL parameters. Note: You will build the Service Manager application in the next tutorial of the series.
public function openServiceManager():Void
{ getURL("serviceManager.cfm?workOrder=" + serviceOrders.selectedItem.data + "&license="
+ license.text + "&status=" + statusComboBox.selectedItem.data);
}