<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:salesforce="http://www.salesforce.com/"
xmlns:view="view.*"
layout="absolute"
applicationComplete="login(event)"
backgroundColor="#FFFFFF"
backgroundGradientColors="[#FFFFFF,#F3F3F3]"
width="700"
height="500"
pageTitle="SalesForce Simple Demo"
viewSourceURL="srcview/index.html"
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
>
<mx:Style source="./assets/Style.css" />
<salesforce:Connection
id = "apex"
serverUrl = "http://www.salesforce.com/services/Soap/u/14.0"
protocol = "http"
/>
<mx:Script>
<![CDATA[
import mx.rpc.AsyncRequest;
import com.salesforce.objects.SObject;
import mx.events.CollectionEvent;
import mx.events.DataGridEvent;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.controls.DataGrid;
import vo.OpportunityVO;
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;
import utils.ParsingUtils;
/**
* you'll notice the [Bindable] tag before the declaration of the variable
*
* this tells our application when its' being compiled to setup listeners for
* when the data is changed to automatically show the changes on the interface
*
* arrayCollection's are bindable, by default regular Array's are not...
*
* think of an ArrayCollection as a wrapper to an array... that just allows the
* interface to bind to it...
**/
[Bindable]
private var acOpportunities:ArrayCollection = new ArrayCollection();
/**
* we need to hold an array collection of items that we've edited that way we can do a
* bulk update when the user clicks "Save All"
*
* we named this "dirty" because the items it holds need to be sent to salesforce to be updated
**/
public var acDirtyOpportunities:ArrayCollection = new ArrayCollection();
/**
* selectedOpportunity is a public variable we will use to be the "editing" opportunity
* we use this variable to pass to the form that is editing the object it is also bindable
*
* if you look toward the bottom of the code, you'll see the compont <view:OpportunityForm vo="{selectedOpportunit} />
*
* this means that when we set this variable in any function, it will automatically be changed in the that form
**/
[Bindable]
public var selectedOpportunity:OpportunityVO;
/**
* the login function gets called from the <mx:Application /> tag
*
* from the event "applicationComplete", this tells the program to run this
* function on applicationComplete.
*
* you'll notice in the function that we setup a "callback" that callback is what is
* called when the result of the function comes back, whether its a good result from
* salesforce or a bad one... (example: a bad login attempt), we do this with the class
* AsyncResponder... its really not that complicated, its simple, all it is, is what
* gets called when we get data back from the salesforce, it takes 2 arguments,
* one is a result function, another is a fault function, the fault gets called when
* the call is bad, and fails, the result is called when its good...
*
**/
private function login(event:Event):void {
apex.protocol = 'http';
var lr:LoginRequest = new LoginRequest();
lr.username = 'yourusername@yahoo.com';
lr.password = 'yourPasswordandSecurityToken'
lr.callback = new AsyncResponder(handleLoadData, handleFault);
apex.login(lr);
}
/**
* handleFault gets called from the login() function
* and is called because we setup a callback to call it when
* the call fails... see the line that has lr.callback = new AsyncResponder( loadData, handleFault );
*
* we use this to simply let us know it failed, this isn't something you would usually show
* to the user, but as a programmer, we like to see the error popup at us while we are programming
* to know something failed... so we setup an Alert to do that by calling Alert.show( string );
**/
private function handleFault(fault:Object):void
{
Alert.show( ObjectUtil.toString(fault) );
}
/**
* handleLoadData is called from our callback that is setup in the login() function as well
* the same as handleFault, this is called when the request is good from the login function, as
* long as its successful, we then query salesforce to get our data,
*
* we also setup a new AsyncResponder to call a function when the data returns
**/
private function handleLoadData(lr:Object):void
{
apex.query( "Select o.StageName, o.Probability, o.Owner.Name, o.OwnerId, o.Name, o.Id, o.Description, o.CloseDate From Opportunity o", new AsyncResponder( handleQueryResult,handleFault) );
}
/**
* handleQueryResult gets called when we return data from our query
* we use this to parse the data and convert it to classes that our
* application understands... we could use generic objects that are
* returned from the query, but it's a lot nicer to use vo's or ValueObjects
* because as a programmer, it allows us to get code hints for properties
* in the object
**/
private function handleQueryResult( event:QueryResult ):void
{
if (event.size > 0)
{
acOpportunities.source = ParsingUtils.convertToArrayCollection( event.records.source,vo.OpportunityVO ).source;
}
}
/**
*
**/
private function handleOpportunityClick():void
{
if( opportunityGrid.selectedItem )
{
selectedOpportunity = opportunityGrid.selectedItem as OpportunityVO;
opportunityForm.visible = true;
opportunityForm.includeInLayout = true;
}
}
/**
* handleSaveAll is called when we click the btnSaveAll
*
* when we edit each item in the datagrid, we store those edited items
* in an array to be ran through an updated
**/
private function handleSaveAll():void
{
trace('save all');
var a:Array = [];
for( var i:int = 0; i < acDirtyOpportunities.length; i++ )
{
var tempVO:OpportunityVO = acDirtyOpportunities.getItemAt(i) as OpportunityVO;
var o:Object = tempVO.toObject();
var so:SObject = new SObject(o);
a.push( so );
}
apex.update( a,new AsyncResponder(handleSaveAllResult,handleFault) );
}
/**
* handleSaveAllResult is called from handleSaveAll, we created an AsyncResponder
* in the class that gets called when the data is returned from salesforce
**/
private function handleSaveAllResult( event:* ):void
{
Alert.show( 'All items saved successfully');
}
/**
* when the item is done editing in the grid, we need to save that
* to the list of items to save when the user clicks "save all"
**/
private function handleEditEnd( event:DataGridEvent ):void
{
var tempVO:OpportunityVO = this.acOpportunities.getItemAt(event.rowIndex) as OpportunityVO;
if( !acDirtyOpportunities.contains(tempVO) )
{
acDirtyOpportunities.addItem(tempVO);
}
}
private function dateLabelFunction( item:Object,column:DataGridColumn ):String
{
var r:String;
r = dateFormatter.format( item[column.dataField] );
return r;
}
]]>
</mx:Script>
<mx:ApplicationControlBar
left="5"
right="5"
top="5"
height="80"
>
<mx:Image
source="./assets/images/mmlogo.gif"
/>
</mx:ApplicationControlBar>
<mx:DateFormatter
id="dateFormatter"
formatString="MM/DD/YYYY"
/>
<mx:VBox
left="5"
right="5"
top="100"
bottom="0"
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
>
<mx:HBox
width="100%"
height="30"
>
<mx:Label text="Double click to edit, or edit Probabilty and CloseDate on the fly" />
<mx:Spacer width="80%" />
<mx:Button
id="btnSaveAll"
label="Save All"
click="handleSaveAll()"
/>
</mx:HBox>
<mx:HBox
width="100%"
height="100%"
>
<mx:DataGrid
width="100%"
height="100%"
id="opportunityGrid"
dataProvider="{acOpportunities}"
doubleClickEnabled="true"
doubleClick="handleOpportunityClick()"
resizeEffect="Resize"
editable="true"
itemEditEnd="handleEditEnd(event)"
>
<mx:columns>
<mx:DataGridColumn
dataField="Name"
editable="false"
/>
<mx:DataGridColumn
dataField="OwnerName"
editable="false"
headerText="Owner"
/>
<mx:DataGridColumn
dataField="Probability"
editable="true"
editorDataField="value"
>
<mx:itemEditor>
<mx:Component>
<mx:NumericStepper
minimum="0"
maximum="100"
/>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
<mx:DataGridColumn
dataField="CloseDate"
editable="true"
itemEditor="mx.controls.DateField"
editorDataField="selectedDate"
labelFunction="dateLabelFunction"
/>
</mx:columns>
</mx:DataGrid>
<view:OpportunityForm
id="opportunityForm"
apex="{apex}"
width="300"
height="97%"
visible="false"
includeInLayout="false"
show="btnSaveAll.visible=false"
hide="btnSaveAll.visible=true"
opportunityVO="{selectedOpportunity}"
/>
</mx:HBox>
</mx:VBox>
</mx:Application>