26 June 2010
ページ ツール |
A basic knowledge of object-oriented programming principles is also helpful.
初級
This tutorial will step you through the process of building a Force.com Flex web application that retrieves, displays, and edits salesforce.com data with Flash Builder for Force.com in an hour.
In this section, you use the salesforce.com website to set up access to salesforce.com data. You will:
If you sign up for a new Force.com Developer account, you will not have added any of your own data to the salesforce.com databases yet. This type of account, though, comes with some sample data that you will take a look at use in this quick start.
In order to build an application that accesses salesforce.com data with the web service API, you must have a Force.com Developer Edition, Enterprise Edition, or Unlimited Edition account. If you do not a have one or these accounts already, start now by getting a free Developer Edition account. Otherwise, proceed to the Grant permission to access data section below.
In order to log in to a Force.com Flex web application not embedded on a salesforce.com VisualForce page, you must either be logging in from an IP address in your companies trusted network or you must include a security token with your login information.
If you are outside the trusted network, you can specify additional IP addresses or ranges of addresses that your organization trusts to access the data. This works if you have a static IP address. If you do not have a static IP address, you need to get a security token that you pass with your username and password when you make requests.
Note: If you are not sure if you are on a trusted network or not, you can skip this section and come back to it later if you get an error when you try to log in to the application you build.

If you are located at a static IP address that is not on your companies trusted network, complete the following steps.

If you are located at a dynamic IP address that is not on your companies trusted network, complete the following steps.

If you are new to salesforce.com, finish up on the salesforce.com website by taking a look at some of the default tables and data that come with your account and then locating the names of the tables and fields you need to use to access them via the web service API.
All Force.com accounts (except the Free Edition) come with a number of standard prebuilt objects that are available for you to use including Account, Contact, Lead and many more. A salesforce.com object is just a database table. For the Developer Edition account, these tables are pre-populated with some same data that you can use to build your first Force.com Flex application. You can customize these prebuilt objects and you can also build your own custom objects (custom database tables) that allow you to store information unique to your organization. See the references at the end of this quick start for more information about working with salesforce.com data.






You are now ready to use Flash Builder for Force.com to build an application that retrieves, displays, and edits salesforce.com data. The first step is to build a basic Force.com Flex application with login functionality.
Note: If you already have Eclipse or Flash Builder installed, you must still install Flash Builder for Force.com as a separate Eclipse instance. Flash Builder for Force.com is not available as a plugin to existing Eclipse instances.
Get started by creating a Force.com Flex project in Flash Builder for Force.com.





If you are logging in from a computer within your companies trusted network, you should successfully log in to your application (see Figure 15).

If you are logging in from a computer outside your companies trusted network, you will get a login must use security token error.
Next, set what salesforce.com objects the application is going to use and then speed up testing of your application during development by adding a default username and password. This way you don't have to manually enter values every time you run the application which gets tedious very quickly.
username TextInput tag and set its text property to your username.<s:TextInput id="username" text="yourUsername"/>
Locate the text property of the password TextInput control and set it equal to your password or if you are outside your companies trusted network, your password appended by your security token. Remember to remove the default values before deploying your application.
<s:TextInput id="password" text="yourPasswordYourToken"/>
Next, use classes in the Force.com Flex framework to retrieve salesforce.com data. To interact with salesforce.com data, you use methods of the class F3WebWrapper (com.salesforce.flexforforce.F3WebWrapper). You use the query() method to retrieve data from the local data store and the save() and deleteItem() methods to update the data in the Force.com cloud.
In this section, you are going to use the F3WebWrapper query() method to retrieve data. You pass to the query() method two arguments, a String of the SQL to execute and a responder function to handle successful or unsuccessful query calls.

_wrapper of type F3WebWrapper. Be sure to select F3WebWrapper from code-hinting so the import statement for the class is written for you (see Figure 17).import com.salesforce.flexforforce.F3WebWrapper;
private var _wrapper:F3WebWrapper;

() function, instantiate the _wrapper variable. It is equal to the wrapper property of the F3WebApplication instance (you can return to the API reference in the browser to confirm this), which in this application has an id of app.protected functionloginCompleteHandler(event:LoginResultEvent):void{
CursorManager.removeBusyCursor();
currentState = "main";
_wrapper=app.wrapper;
}
loginCompleteHandler() function, call the F3WebWrapper query() method and pass to it a String equal to the text for the query statement you want to execute against Force.com: retrieve the Id and Name fields and order by the Name field. This query statement must be written using a subset of SOQL, the Salesforce.com Object Query Language. Unlike Name, Id field was not listed as a field for the Contact object on salesforce.com. Every Force.com object, though, has an Id field that uniquely identifies it. You are not going to display the Id field in your application, but you need to retrieve it so you can later update these records on Force.com.
Note: You cannot use * in the SOQL statements for Force.com Flex web applications.
_wrapper.query("select Id, Name from Contact order by Name");
query() method argument, create a new instance of the mx.rpc.Responder class and specify a new function called contactQueryResultHandler to handle the results and a function called queryFaultHandler to handle the faults. Be sure to select mx.rpc.Responder from code-hinting so the import statement is written for you.import mx.rpc.Responder;
protected function loginCompleteHandler():void {
CursorManager.removeBusyCursor();
currentState = "main";
_wrapper=app.wrapper;
_wrapper.query("select Id, Name from Contact order by Name",
new mx.rpc.Responder(contactQueryResultHandler,queryFaultHandler));
}
query() method of the F3WebWrapper class (see Figure 18). The types of objects passed to the result and fault handlers are specified here.
contactQueryResultHandler that receives one argument called data of type ArrayCollection and returns nothing. Successful query calls return an ArrayCollection of Account objects. The ArrayCollection class is a Flex framework class that essentially wraps an Array so that its contents are monitored for changes. Be sure to select ArrayCollection from code-hinting so the import statement is written for you.import mx.collections.ArrayCollection;
protected function contactQueryResultHandler(data:ArrayCollection):void{
}
queryFaultHandler that receives one argument called message of type F3Message and returns nothing. When a query fails, an F3Message object (com.salesforce.notifications.F3Message) is returned which has a description property. Be sure to select F3Message from code-hinting so the import statement is written for you.import com.salesforce.notifications.F3Message;
protected function queryFaultHandler(message:F3Message):void{
}
queryFaultHandler(), use the Flex Alert component to display a pop-up box by calling its static show() method and passing to it the message you want to display, message.description , and a title for the box, "Error".Alert.show(message.description,"Error");
A good practice before you write any display code is to use the Flash Builder debugger to look at the data (or error) returned from your query call.


contactQueryResultHandler() function (see Figure 21). You should see a blue circle in the marker bar next to that line of code. You can double-click the breakpoint in the marker bar to remove it or right-click it and select Toggle Breakpoint.


this and data . this is the instance of the application, SalesforceContacts. data is the argument for the contactQueryResultHandler() function, an instance of the ArrayCollection class.
data . You should see all the properties and their values for the ArrayCollection instance (see Figure 25).
Id and Name properties.
Properties with green circles are public properties. Those with red squares are private properties. Properties inherited from superclasses are grouped in a separate tree node called [inherited] to help reduce the number of variables visible at one time.
Next, you are going to retrieve more fields of the Contact objects. One way to find out the names of the fields is to return to salesforce.com and look up the fields under Setup > App Setup > Customize > Contacts > Fields. This works for the simple fields like Phone or Email but not for the compound fields, like MailingAddress. For the latter, salesforce.com tells you there is a field called MailingAddress of type Address, but you cannot make a web service call to retrieve the MailingAddress field, you have to request the individual MailingStreet, MailingCity, MailingState, MailingPostalCode, and MailingCountry fields that make up this compound object.
One way to discover all the possible fields for an object is to create a WSDL (a Web Services Description Language file) with salesforce.com and then create a salesforce data service in Flash Builder for Force.com based upon this WSDL. Although not necessary, this is convenient for development as it creates client side ActionScript equivalents of the server side Force.com objects enabling you to discover all the properties, get code-hinting for these properties, and also get compile-time checking for them which reduce errors.
First, you need to return to salesforce.com and generate a WSDL that contains information about what data can be accessed via web services.


You are now ready to create a salesforce data service in Flash Builder based on this WSDL.





Now, return to your query and retrieve additional fields for the Contact objects.
loginCompleteHandler() and change the SQL statement to also retrieve the Email , Phone , MailingStreet , MailingCity , MailingState , MailingPostalCode , and MailingCountry fields._wrapper.query("select Id,Name,Email,Phone,MailingStreet,MailingCity,MailingState,MailingPostalCode,MailingCountry
from Contact order by Name",newmx.rpc.Responder(contactQueryResultHandler,faultHandler));

Now that you have successfully retrieved salesforce.com data, you are ready to display the data in the application. The Force.com Flex framework contains several components to make displaying and editing your salesforce.com data very easy. You use a LabelAndField (com.salesforce.flexforforce.LabelAndField) component for each field of an object you want to display. The LabelAndField component handles displaying, formatting, editing, and validating that field. If you want to display multiple fields of an object, you place multiple LabelAndField components inside a FieldContainer (com.salesforce.flexforforce.FieldContainer). You populate these components by using their render() method when you get the results back from your query.
Start by using a LabelAndField component to display the value of one field of an object.
<s:VGroup> inside the Group container.width to 400.<s:VGroup width="400" paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10">
<s:Label/> tag inside the VGroup.nameField . You can just start typing "La" and then select LabelAndField in code-hinting and the tag prefix will be written for you (see Figure 35).
<s:VGroup width="400 paddingBottom="10"
paddingLeft="10" paddingRight="10"
paddingTop="10">
<flexforforce:LabelAndField id="nameField"/>
</s:VGroup>
field property to Contact.Name, the name of the salesforce.com object and its field you want to display in this component.<flexforforce:LabelAndField id="nameField" field="Contact.Name"/>
Note: The LabelAndField class combines the Force.com Flex FieldElement component (com.salesforce.flexforforce.FieldElement) and a Flex Spark Label. Use the FieldElement instead of the LabelAndField if you want the same behavior as a LabelAndField but don't want a field label displayed.
startState property to Inline Edit. When the cursor is inside the quotation marks for the value, you can press Ctrl-Spacebar to select one of the possible options (see Figure 36). If you don't specify a value for startState , you will get a runtime error when you run the application. You will explore the edit states of the LabelAndField in the next section.
<flexforforce:LabelAndField id="nameField"
field="Contact.Name" startState="Inline Edit"/>
contactQueryResultHandler() function, use the LabelAndField's render() method to display the name of the first item returned by the query.protected function contactQueryResultHandler(data:ArrayCollection):void{
nameField.render(data[0]);
}

To display multiple fields of an object, place multiple LabelAndField components inside a FieldContainer.
id from the first LabelAndField as it will no longer be used.<s:VGroup width="400" paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">
<flexforforce:LabelAndField id="nameField"
field="Contact.Name" startState="Inline Edit"/>
<flexforforce:LabelAndField field="Contact.Email"/>
<flexforforce:LabelAndField field="Contact.Phone"/>
<flexforforce:LabelAndField field="Contact.MailingStreet"/>
</s:VGroup>
contactContainer , a width of 100%, and move the startState property from the first LabelAndField to the FieldContainer. You can also remove the id property from the first LabelAndField because it will no longer be used.<s:VGroup width="400" paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">
<flexforforce:FieldContainer id="contactContainer" width="100%" startState="Inline Edit">
<flexforforce:LabelAndField field="Contact.Name"/>
<flexforforce:LabelAndField field="Contact.Email"/>
<flexforforce:LabelAndField field="Contact.Phone"/>
<flexforforce:LabelAndField field="Contact.MailingStreet"/>
</flexforforce:FieldContainer>
</s:VGroup>
contactQueryResultHandler() function, replace the existing code with code to render the first account to the new FieldContainer. The FieldCollection does not have a render() method, but it has a fieldCollection property which is an instance of the FieldCollection class (com.salesforce.flexforforce.FieldCollection) which does. The FieldCollection manages the data to be displayed in the container.protected function contactQueryResultHandler(data:ArrayCollection):void{
contactContainer.fieldCollection.render(data[0]);
}

<flexforforce:LabelAndField field="Contact.MailingStreet[Group]"/>

Next, add a Flex DropDownList component (spark.components.DropDownList) to switch between the contacts.
_contacts of type ArrayCollection. This variable will hold all the retrieved Contact data. It needs to be bindable so any views bound to it will get updated when its value changes. If you are new to Flex and this concept, see the references at the end of this quick start to learn more.[Bindable] private var _contacts:ArrayCollection;
onContactQueryResult() function, set the _contacts variable equal to the data returned from the query.protected function contactQueryResultHandler(data:ArrayCollection):void{
contactContainer.fieldCollection.render(data[0]);
_contacts=data;
}
id of contactList.<s:VGroup width="400" paddingBottom="10" paddingLeft="10"
paddingRight="10" paddingTop="10">
<s:DropDownList id="contactList"/>
<flexforforce:FieldContainer id="contactContainer"
width="100%" startState="Inline edit">
dataProvider property equal to the _contacts variable you created. Use data binding {} to bind this to this dynamic value so that when its value changes at runtime the list will be updated.<s:DropDownList id="contactList" dataProvider="{_contacts}"/>
labelField property to Name, the name of the Contact object property you want to display in it. If you did not set this property, [Object DynamicEntity] would be displayed in the DropDownList for all contacts.width property to 200 so it is big enough to display the full contact names.change event and set the event handler to be a function called contactListChangeHandler . Pass the event object to the event handler.<s:DropDownList id="contactList" dataProvider="{_contacts}"
labelField="Name"
width="200" change="contactListChangeHandler(event)"/>
contactListChangeHandler with one argument of type Event and a return type of void. protected function contactListChangeHandler(event:Event):void{
}
contactListChangeHandler() function, render to the FieldCollection the contact that is selected in the DropDownList. This will change the contact data displayed in the LabelAndField components.contactContainer.fieldCollection.render(event.currentTarget.selectedItem);
onContactQueryResult() function, set the selectedIndex of the DropDownList to the first contact.contactList.selectedIndex=0;

In addition to formatting and displaying the data for a object field, the Force.com Flex LabelAndField (and FieldElement) component also handles editing the value of that field, validating the new value entered, and providing a message to the user if validation fails. After new data has been entered by the user, the new data must be explicitly committed to the Force.com cloud.
You can edit data in your existing LabelAndField components.



Note: If the field you were editing was required, a vertical, red line would appear to the left of the input box just like on salesforce.com.




Note: If you are using the sample data for a Force.com Developer account, for some of the contacts you will see the entire address appear in the MailingStreet input control instead of in separate controls. For these contacts, the entire address was erroneously entered into the MailingStreet field instead of in the separate fields.
Before saving the data, look at a second possible edit mode. The LabelAndField and FieldContainer components actually have three modes you can use for editing field data: Create, Inline Edit, and Full Edit. You set the edit mode by setting the startState property to one of these values.
contactContainer tag and set the startState property equal to Full Edit. Be sure to choose the value using code-hinting so you get the correct spelling and capitalization.<flexforforce:FieldContainer id="contactContainer"
width="100%"
startState="Full Edit">
width of the VGroup from 400 to 100%.
startState of the contactContainer tag back to Inline Edit and the width of the VGroup back to 400.There are three steps to saving data. First, you must provide a UI control, like a button, for starting the save process. Second, you must save the changes made in the interface to the Contact object that is being rendered in the FieldContainer. This object that is being displayed, monitored, validated and so on by the FieldContainer is called the managed object. Third, you need to actually commit the changes (saving the managed object) to the Force.com cloud.
label of Save and a click event handler equal to saveButtonClickHandler().<s:Button label="Save" click="saveButtonClickHandler()"/>
saveButtonClickHandler with no arguments and that returns no value.protected function saveButtonClickHandler():void{
}
saveButtonClickHandler(), call the updateObject() method of the FieldContainer's fieldCollection property which is an instance of the FieldCollection class. The LabelAndField and FieldContainer components do not have a property that allows you to access the data they are managing, but their sub-components, the FieldElement and FieldCollection classes do. Both classes have a read-only property called managedObject , which refers to the data being managed by that component or collection of components.protected function saveButtonClickHandler():void{
contactContainer.fieldCollection.updateObject();
}
updateObject() method a new instance of the mx.rpc.Responder class with a result handler called updateResultHandler and a fault handler called updateFaultHandler . When the updateObject() method is invoked, the data fields of the corresponding FieldElement objects are checked to make sure that valid data has been entered for each of them. The result method of the responder is invoked if all associated data fields pass validation and the managed object is successfully updated; it receives one argument equal to the managed object, the contact object being manipulated. The fault handler is invoked if any of the fields fail validation and it receives an array of invalid FieldElement objects.protected function saveButtonCLickHandler():void{
contactContainer.fieldCollection.updateObject(newmx.rpc.Responder(updateResultHandler,updateFaultHandler));
}
updateResultHandler that receives one argument called data of type DynamicEntity and returns no value. Be sure to choose DynamicEntity from code-hinting so the import statement is written for you.import com.salesforce.flexforforce.DynamicEntity;
protected function updateResultHandler(data:DynamicEntity):void{
}
You saw when debugging your application earlier, that when items are retrieved from the Force.com cloud, they are created as DynamicEntity objects. DynamicEntity is a dynamic class defined as part of the Force.com Flex framework.
updateFaultHandler that receives one argument called data of type Array and returns no value.protected function updateFaultHandler(data:Array):void{
}
updateFaultHandler(), use the Flex Alert component to display a pop-up box by calling its static show() method and passing to it a message and title.Alert.show("Error updating the contact","Error");
Next use the F3WebWrapper save() method to commit the changes to the Force.com cloud.
() , call the save() method of the F3WebWrapper instance and pass to it data , the instance of the managed instance that you want to commit.protected function updateResultHandler(data:DynamicEntity):void{
_wrapper.save(data);
}
save() method argument equal to a new instance of the mx.rpc.Responder class and specify a function called saveResultHandler as the result handler and saveFaultHandler as the fault handler._wrapper.save(data, new mx.rpc.Responder(saveResultHandler,saveFaultHandler));
saveResultHandler that receives one argument called message of type F3Message, returns nothing, and displays a pop-up with a message that the save was successful.protected function saveResultHandler(message:F3Message):void{
Alert.show("Contact updated on salesforce.com","Success");
}
saveFaultHandler that receives one argument called message of type F3Message, returns nothing, and displays a pop-up with a message that the save failed.protected function saveResultHandler(message:F3Message):void{
Alert.show("Contact was not updated on salesforce.com","Error");
}
Finally, go make data changes that get committed to the Force.com cloud.


saveResultHandler() function, re-render the data in the FieldContainer.protected function saveResultHandler(message:F3Message):void{
Alert.show("Contact updated on salesforce.com","Success");
contactContainer.fieldCollection.render(
contactContainer.fieldCollection.managedObject);
}

Congratulations! You have now successfully created your first Force.com Flex web application that retrieves, displays, and edits salesforce.com data.
In this tutorial, you created a Force.com Flex web application built with Flash Builder for Force.com that retrieves, displays, and edits salesforce.com data using the Force.com Flex framework.
To learn more about using salesforce.com and the Force.com platform, refer to the following resources:
To learn more about the Force.com Flex classes and components, refer to the following resources:
To learn more about creating and customizing Flex 4 applications, refer to the following resources:
To learn about building Force.com Flex desktop applications, refer to the following resources: