Flex Hello World

Abstract

This is a simple tutorial showing how to use the Force.com Toolkit for Adobe AIR and Flex. In a very few lines of ActionScript Code and MXML, you will create a simple data-bound grid control that has useful default behaviors such as sorting, column resizing and column reordering.

If you just want to cut and paste the code you can find it at the end of this article.

Creating the Application

The following steps walk you through creating the Flex application. A later section will show how to embed this application in your Force.com project.

Create the Project

The first step is to create a new Flex Project or open an existing Flex Project. Next, create a new MXML Application in the project. For the sample the MXML application is named SimpleGrid. If the application file is opened in the source editor, click the button to switch to Design.

Add a Grid Component

Drag a Grid component onto the design surface. For the layout properties select to constrain the four edges of the grid and enter 10 into each of the constraint boxes. This will cause the grid to fill the entire surface with a 10 pixel margin around it.

Switch back over to the source view and remove the columnHeading attributes for each of the three columns that were automatically generated for the grid.

Add the Flex Toolkit for Force.com

Download the Force.com Toolkit for Adobe AIR and Flex. In the toolkit you will find a file named as3Salesforce.swc in the bin folder. You can unzip or move the toolkit folder anywhere you want on your hard drive.

Once you have obtained the toolkit you will need to add it to the build path for your project. Right-click the project created above and select "Properties" from the pop-up menu. In the properties dialog select "Flex Build Path" from the list of items and then click the "Library Path" button in the right hand pane. Click the "Add SWC" button and navigate to where you saved the toolkit.

Click the "OK" button and you are now ready to use the toolkit in your Flex application.

Writing the Code

While still in source view place your cursor directly before the <mx:Grid> tag and enter a new line. Begin typing <Connection and when the salesforce:Connection tag is displayed, selected and hit enter.

The Connection tag needs, at minimum, two attributes to be set. The first is the id attribute. This is the variable name by which you can reference the connection object. For the sample enter "apex". The second attribute is the server url which indicates the endpoint of the Force.com Web Services API. For the current version of the API enter "https://www.salesforce.com/services/Soap/u/9.0". Do not try to use the Enterprise endpoint. The toolkit is based on the Partner wsdl and therefore needs to use /u/x.x. Be sure to close the connection with "/>".

Create a <mx:Script> block below the connection tag. Cut and paste the code shown below into the script block.

	import mx.collections.ArrayCollection;
	import com.salesforce.results.QueryResult;
	import mx.utils.ObjectUtil;
	import mx.controls.Alert;
	import com.salesforce.AsyncResponder;
	import com.salesforce.objects.LoginRequest;
	
	private function login(event:Event):void {
		var lr:LoginRequest = new LoginRequest();
		lr.server_url = parameters.server_url;
		lr.session_id = parameters.session_id;
		lr.callback = new AsyncResponder(loadData, handleFault);
		apex.login(lr);
	}
	[Bindable]
	private var accountList:ArrayCollection = new ArrayCollection();
	
	private function handleFault(fault:Object):void {
		Alert.show(ObjectUtil.toString(fault));
	}
	
	private function loadData(lr:Object):void {
		apex.query("Select Name, Phone, Type From Account", new AsyncResponder(
			function(qr:QueryResult):void {
				if (qr.size > 0) {
					accountList = qr.records;
				}
			}, 
			handleFault)
		);
	}

Binding the DataGrid

To bind the grid you need to add the dataProvider attribute to the grid control and set the dataField attributes for the columns. In this case the dataProvider is accountList. This must be specified in curly braces. For information about curly braces, search the help docs in Flex Builder.

The dataFields do not need curly braces and must match exactly the field names that are returned from your query. In this case the field names are Name, Phone and Type.

Your data grid is now bound to the accountList variable and when the contents of that variable change, so will the data that is displayed in the grid.

Hooking the Creation Complete Event

You want to have the login function run only after the entire application has been generated on the client. To ensure this is the case, you will handle the creationComplete event on the Application object. In the Application tag enter 'creationComplete="login(event)"'.

You have now completely wired up the grid to receive data from Force.com.

Embedding the Application

Let's now look at how to embed the application in a Force.com application.

Import as Static Resource

To embed the Flex application on Force.com, you need to embed it as part of a Visualforce page. The first part of this process is uploading the Flex application as a "static resource" - which can then be referenced from the Visualforce page. Read Delivering Static Resources with Visualforce for more information about static resources.

In your Flex project you should see a "bin" folder. This folder will contain a <application name>.swf file. This is the file to upload. If you need to modify the Flex app, simply make your changes, save the changes (causing Flex Builder to regenerate the swf) and just re-upload the swf file.

To upload, navigate to Setup | Develop | Static Resources and upload the file. Let's assume you call it Flex_Hello_World_SWF.

Embedding in a Visualforce Page

To create a simple page, log on to Force.com and navigate to Setup | Develop | Pages and create a new Visualforce page. The following code will embed the Flex application (now uploaded as a static resource):

<apex:page>
          
    <apex:pageBlock title="Flex Hello World">
        <apex:flash src="{!$Resource.Flex_Hello_World_SWF}" width="500" height="300"
           flashvars="sid={!$Api.Session_ID}&surl={!$Api.Partner_Server_URL_90}"/>
    </apex:pageBlock>
      
</apex:page>

Note how we use Visualforce merge fields to pass in the session and API end point to the Flex application. You can use this mechanism to pass in additional parameters as well. This same technique (using the <apex:flash> Visualforce component) can be used for embedding any Flex component you make.

That's it - you now have a Visualforce page that runs your Flex application.

Resources

Full MXML File

Here's the complete listing for the MXML file.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application creationComplete="login(event)" xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:salesforce="http://www.salesforce.com/">
	<salesforce:Connection id="apex" serverUrl="https://www.salesforce.com/services/Soap/u/9.0" />
	
<mx:Script>
	<![CDATA[
			import mx.collections.ArrayCollection;
			import com.salesforce.results.QueryResult;
			import mx.utils.ObjectUtil;
			import mx.controls.Alert;
			import com.salesforce.AsyncResponder;
			import com.salesforce.objects.LoginRequest;
			
			private function login(event:Event):void {
				var lr:LoginRequest = new LoginRequest();
				lr.server_url = parameters.server_url;
				lr.session_id = parameters.session_id;
				lr.callback = new AsyncResponder(loadData, handleFault);
				apex.login(lr);
			}

			[Bindable]
			private var accountList:ArrayCollection = new ArrayCollection();
			
			
			private function handleFault(fault:Object):void {
				Alert.show(ObjectUtil.toString(fault));
			}
			
			private function loadData(lr:Object):void {
				apex.query("Select Name, Phone, Type From Account", new AsyncResponder(
					function(qr:QueryResult):void {
						if (qr.size > 0) {
							accountList = qr.records;
						}
					}, 
					handleFault)
				);
			}
		
	]]>
</mx:Script>	
	<mx:DataGrid dataProvider="{accountList}" left="10" right="10" top="10" bottom="10">
		<mx:columns>
			<mx:DataGridColumn dataField="Name"/>
			<mx:DataGridColumn dataField="Phone"/>
			<mx:DataGridColumn dataField="Type"/>
		</mx:columns>
	</mx:DataGrid>
	
</mx:Application>


Authentication Problems

I wasn't able to get the flex to authenticate with the above technique. The technique described in this developer discussion did the trick for me.