Passing Data between views in Adobe Flex (Actionscript) - apache-flex

Ive read a ton of online tutorials about this and cant seem to get a definite answer...
View1.mxml
navigator.pushView(views.view2, {response:"BLAH"});
View2.mxml
<fx:Script>
<![CDATA[
var result:String = // FIRST VIEW RESPONSE WHICH = BLAH
]]>
</fx:Script>
How is this done? Surely it should be simple? All the tutorials online seem very indepth!
Thanks
Phil

The property you are looking for is called data. It will get set AFTER construction. So, once data is set, you want to access data.response.

Got it
navigator.pushView(views.view2, "BLAH");
var result:String = String(data);
Duhhh

Related

In Flex, can I send HTTPService POST-request instead of GET-request?

There is known issue in Internet Explorer (6,7) when Flex (HTTPService) is loading XML through SSL. Flash Player is throwing Error #2032: Stream Error in that case.
As advised by Microsoft and others, "Cache-Control: no-store" should be set on the server side to resolve the issue.
Unfortunately, I do not have access to application's backend, and thus I should solve it through Flex.
My goal is to load xml file with configurations at runtime.
Custom headers for GET requests are not allowed in Flex (let me know, if I am wrong). Thus I decided to accomplish my goal with POST request, and surprisingly it worked very well.
Here is the code I came with:
var httpService:HTTPService = new HTTPService();
httpService.url = 'config.xml';
httpService.method = 'POST';
httpService.requestTimeout = 10;
httpService.contentType = "application/xml";
httpService.headers["Cache-Control"] = "no-store";
httpService.resultFormat = "e4x";
var localResponder:Responder = new Responder(
function(event:ResultEvent):void {
//event.result returns the required xml configuration
},
function(event:FaultEvent):void {
});
var token:AsyncToken = httpService.send({});
token.addResponder(localResponder);
My question is: Could there be any side effects, when POST request is sent instead of GET request?
UPDATE:
To prove that GET-requests are stripped of headers, I've taken the code provided by #Reboog711 and created a little application. Here is the code:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.rpc.http.HTTPService;
protected function sendHTTPRequest(event:MouseEvent):void
{
var httpService:HTTPService = new HTTPService();
httpService.url = 'xml.xml';
var headerData : Object = new Object();
headerData['Cache-Control'] = 'no-store';
httpService.headers = headerData;
httpService.send();
}
]]>
</fx:Script>
<s:Button label="SEND HTTP REQUEST"
horizontalCenter="0" verticalCenter="0" click="sendHTTPRequest(event)"/>
</s:Application>
And here is what I see in Charles application, when I send that HTTP-request.
You can test it yourself right here. Moreover, while I was trying to solve my problem, I've seen many evidences that GET-requests couldn't be sent with custom headers. You may take a look here.
Thanks!
You should be able to add headers to an HTTPService request without any problems. I have done it before, when integrating a Flex app with the YouTube APIs. Conceptually, it should be like this:
var httpService:HTTPService = new HTTPService();
var headerData : Object = new Object();
headerData['Cache-Control'] = 'no-store';
http.headers = headerData;
If you perform a Google Search other links come up. So long as your service supports both GET and POST requests; I do not know why you would experience any issues.

Sort Grouped Columns in AdvancedDatagrid

I#m looking for a solution to sort all grouped colums in advancedDatagrid. It should be the same behavior like clicking in a columns head.
Please note, i'm not looking for a solution to sort the fields IN a the grouping. There is working solution named compareFunction.
But I'm not able to sort the two rows in my picture by column "Einnahmen". Sorry for the german word.
Do you have an Idea?
Thank you
Frank
If you're looking to start the application with sorted columns, you need to simulate a header click upon creation/dateprovider update.
Try this:
<mx:AdvancedDataGrid id="adg"
updateComplete="adg.dispatchEvent(new AdvancedDataGridEvent(AdvancedDataGridEvent.HEADER_RELEASE, false, true, 3, 'Einnahmen'))">
<mx:columns>
...
<mx:AdvancedDataGridColumn dataField="Einnahmen" sortDescending="true" />
</mx:columns>
</mx:AdvancedDataGrid>
I haven't tried this for grouped collections but let me know how this works.
EDIT:
I didn't know you were building your dataProvider through ActionScript. You should still be able to run the Sort on your collection after you've finished putting it together though.
Another option would be to extend the AdvancedDataGrid component and override the set dataProvider method to sort the data as soon as you bind it. Here's an example another developer provided (source) for the Tree control, but the same concept could probably be used on the AdvancedDataGrid.
Original answer:
Assuming you're just trying to sort the top level "Einnahmen" values (which it looks like you are from your screenshot), I would manually sort your dataProvider after data is returned from whatever service you're using to get your data.
Here's a very basic example of manually sorting your collection.
[Bindable] public var MyDataList:ArrayCollection;
private var einnahmenSortField:SortField = new SortField("Einnahmen", true, false);
private var theSort:Sort = new Sort();
// Called after data is returned from the remote service call to sort the data
public function SetMyDataList(returnedList:ArrayCollection):void
{
MyDataList = returnedList;
if (theSort == null)
{
theSort = new Sort();
theSort.fields = [einnahmenSortField];
}
MyDataList.sort = this.theSort;
MyDataList.refresh();
}
To convert it to HierarchicalData for use in your AdvancedDataGrid, just create a new instance of HierarchicalData and assign it to your AdvancedDataGrid like this:
var hd:HierarchicalData = new HierarchicalData(myDataList);
hd.childrenField = "MyChildField";
myAdvancedDataGrid.dataProvider = hd;
Did you try to set the 'sortExpertMode="true"' in the AdvancedDataGrid tag? Please find the sample code below:
<mx:AdvancedDataGrid height="318"
id="dataSetsDG"
allowMultipleSelection="false"
folderClosedIcon="{null}"
folderOpenIcon="{null}"
defaultLeafIcon="{null}"
left="28"
top="162"
rowCount="11"
width="70%"
displayItemsExpanded="true"
sortExpertMode="true">
I used 'HierarchicalData' as the dataprovider for the AdvancedDataGrid.I also created the HierarchialData from the ArrayCollection, the sort order was maintained and it works like a charm.You can give it a try!
Please find the Actionscript code and a sample screenshot.
public function createHierarchialResultVO(results:ArrayCollection):ArrayCollection
{
[ArrayElementType("ResultsVO")]
var dpHierrarchy:ArrayCollection = new ArrayCollection();
for each(var result:Result in results)
{
var resultVO:ResultsVO= new ResultsVO();
resultVO.resultName = result.resultName;
resultVO.runDate = result.runDate.toString();
resultVO.type="header";
var childrens:ArrayCollection = new ArrayCollection();
for each(var processDetails:ProcessDetails in result.details)
{
var children:ResultsVO= new ResultsVO();
children.files =result.fileCount;
children.status=result.status;
children.type="result";
}
resultVO.children =children;
dpHierrarchy.addItem(resultVO);
}
return dpHierrarchy;
}

Load Content into TextInput Flex?

I've got content coming into my application using a query and an ArrayCollection. I know how to display the content into a DataGrid by using the dataProvider propriety, but I'd like to use TextInput components and drop the DataGrid altogether.
Does anyone have any examples or information on how I would go about doing this?
Thanks!
Thank you for the insight - invertedSpear
I'm still having a problem all that displays is [object,object]
Here is a bit of my code.
[Bindable]
private var acCon:ArrayCollection;
private function reData():void //RETRIEVE DATA
{
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = sqlConn;
stmt.text = "SELECT * FROM person";
stmt.execute();
var result:SQLResult = stmt.getResult();
acCon = new ArrayCollection(result.data);
}
<mx:Repeater id="repeater1" dataProvider="{acCon}">
<mx:Label id="Label1" text="{repeater1.currentItem}"/>
</mx:Repeater>
Any thoughts?
Your question is not clear. The format of your query result and exactly how you are wanting to display them make a difference in this.
Things you need to do no matter what the format.
1) make sure you have a bindable variable to store your query result in:
[Bindable] public var myArrayCollection:ArrayCollection = new ArrayCollection();
2) assign you query result to this.
3) probably going to need to use a loop or a repeater based on your results length, not sure what your result looks like so you will have to figure this out.
4) assign the values to text boxes.
<mx:Text text="{myArrayCollection.FieldName}">
This answer is my best guess to what your question is. Please edit your question to make it more clear if this answer doesn't work for you.
Looking at your code example that's now up I am guessing you are very close, your repeater is kind of like your query result. Current item is like a row of your query. you probably just need to add the field name to it. So Maybe:
<mx:Label id="Label1" text="{repeater1.currentItem.LastName}"/>

HTTP Basic Authentication with HTTPService Objects in Adobe Flex/AIR

I'm trying to request a HTTP resource that requires basic authorization headers from within an Adobe AIR application. I've tried manually adding the headers to the request, as well as using the setRemoteCredentials() method to set them, to no avail.
Here's the code:
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
private function authAndSend(service:HTTPService):void
{
service.setRemoteCredentials('someusername', 'somepassword');
service.send();
}
private function resultHandler(event:ResultEvent):void
{
apiResult.text = event.result.toString();
}
private function resultFailed(event:FaultEvent):void
{
apiResult.text = event.fault.toString();
}
]]>
</mx:Script>
<mx:HTTPService id="apiService"
url="https://mywebservice.com/someFileThatRequiresBasicAuth.xml"
resultFormat="text"
result="resultHandler(event)"
fault="resultFailed(event)" />
<mx:Button id="apiButton"
label="Test API Command"
click="authAndSend(apiService)" />
<mx:TextArea id="apiResult" />
However, a standard basic auth dialog box still pops up prompting the user for their username and password. I have a feeling I'm not doing this the right way, but all the info I could find (Flex docs, blogs, Google, etc.) either hasn't worked or was too vague to help.
Any black magic, oh Flex gurus? Thanks.
EDIT: Changing setRemoteCredentials() to setCredentials() yields the following ActionScript error:
[MessagingError message='Authentication not supported on DirectHTTPChannel (no proxy).']
EDIT: Problem solved, after some attention from Adobe. See the posts below for a full explanation. This code will work for HTTP Authentication headers of arbitrary length.
import mx.utils.Base64Encoder;
private function authAndSend(service:HTTPService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false; // see below for why you need to do this
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
Finally received some attention from Adobe and got an answer on this. The problem with long HTTP Authentication headers is that, by default, the Base64Encoder class will inject newline characters every 72 characters. Obviously that causes a chunk of the base-64 encoded string to be interpreted as a new header attribute, which causes the error.
You can fix this by setting (in the above example) encoder.insertNewLines = false; The default setting is true.
I've fixed the above code to work for arbitrarily long Authentication strings.
Ah. The pain, the suffering. The sheer misery.
While you've figured out how to add a header before making your call, the nasty truth is that somewhere deep down in the Flash/browser integration space your headers are being removed again.
From my blogpost last year at verveguy.blogspot.com
So I have unraveled the Truth. (I think)
It's more tortured than one would imagine
1/ All HTTP GET requests are stripped of headers. It's not in the Flex stack so it's probably the underlying Flash player runtime
2/ All HTTP GET requests that have content type other than application/x-www-form-urlencoded are turned into POST requests
3/ All HTTP POST requests that have no actual posted data are turned into GET requests. See 1/ and 2/
4/ All HTTP PUT and HTTP DELETE requests are turned into POST requests. This appears to be a browser limitation that the Flash player is stuck with. (?)
What this boils down to in practical terms is that if you want to pass headers in all requests, you should always use POST and you should find another way to communicate the semantics of the operation you "really wanted". The Rails community have settled on passing ?_method=PUT/DELETE as a work around for the browser problems underlying 4/
Since Flash adds the wonderful header stripping pain on GET, I'm also using ?_method=GET as a workaround for that. However, since this trips up on 3/,
I am passing a dummy object as the encoded POST data. Which means my service needs to ignore dummy posted data on a ?_method=GET request.
Crucial at this point to know about 2/. That wasted a bunch of my time.
I've built all of this handling into a new RESTService class with MXML markup support so it's possible to pretend this doesn't exist on the client side.
Hope this helps someone.
The setCredentials() & setRemoteCredentials() methods are intended for use with Flex/LiveCycle Data Services, so they probably don't apply in your case.
This ought to work for you. I was able to reproduce this behavior on my server, and this fix seems to have done the trick; it still seems a bit odd this isn't more API-user-friendly, considering how common a use case you'd think it were, but nonetheless, I've tested and verified this works, given a valid SSL cert:
private function authAndSend(service:HTTPService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode("someusername:somepassword");
service.headers = {Authorization:"Basic " + encoder.toString()};
service.send();
}
Hope it helps! And thanks for posting -- I'm sure I would've run into this one sooner or later myself. ;)
This really has helped me! Thanks!
I use Flex Builder 3
One note: WebService's property headers is read only.
So I tried to use httpHeaders. It works!
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("test:test");
sfWS.httpHeaders = {Authorization:"Basic " + encoder.toString()};
I had the same problem while consuming HTTP Basic Authenticated Webservice. This is my solution; it works fine:
private function authAndSend(service:WebService):void
{
var encoder:Base64Encoder = new Base64Encoder();
encoder.insertNewLines = false;
encoder.encode("user:password");
service.httpHeaders = { Authorization:"Basic " + encoder.ToString() };
service.initialize();
}
usage
authAndSend(WebService( aWebServiceWrapper.serviceControl));
Try using setCredentials rather than setRemoteCredentials and failing that, using Fiddler/Charles to find out what headers are being sent with the request.
Also, just so other people don't spend 10 minutes working out why the correct example doesn't quite work asis, you need to import the mx.utils.Base64Encoder package eg:
import mx.utils.Base64Encoder;
At the beginning or somewhere within the CDATA area. I'm new to flex so this wasn't quite obvious at first.
This is how its done.
import mx.utils.Base64Encoder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
var _oHttp:HTTPService = new HTTPService;
var sUsername:String = "theusername"
var sPassword:String = "thepassword";
var oEncoder:Base64Encoder = new Base64Encoder();
oEncoder.insertNewLines = false;
oEncoder.encode(sUsername + ":" + sPassword);
_oHttp.method = "POST";
_oHttp.headers = {Authorization:"Basic " + oEncoder.toString()};

adobe flex problem with Base64Encoder

in the following code :
var benq:Base64Encoder = new Base64Encoder();
benq.encode("force",0,5);
var tmp:String = benq.toString();
'tmp' turns out to be an empty string, i.e. with length 0.
why?
how to encode a string using base64encoder?
Are you sure that your code isn't working.
I just copied and pasted it into a test app and it returned tmp as 'Zm9yY2U='
Are you doing anything else to the var tmp? if debugging make sure that it has processed the var tmp:String.... line when your checking the output
<?xml version="1.0" encoding="utf-8"?><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="white"
creationComplete="but1.label = encodeit()">
<mx:Script>
<![CDATA[
import mx.utils.Base64Encoder;
private function encodeit(): String {
var benq:Base64Encoder = new Base64Encoder();
benq.encode("force",0,5);
var tmp:String = benq.toString();
return tmp;
}
]]>
</mx:Script>
<mx:Button
id="but1"
width="100"
height="100"
/></mx:Application>
Are you using Flex 3, as it seems to be a new feature? Also try encoding into a bytearray using encodeBytes and using encodeUTFBytes, perhaps these work better.
Online reference is available from Adobe, but I guess you know that.
Ok, it is working.
The code that I posted was different from what I was actually using.
I skipped over the fact that calling toString() for Base64Encoder
clears its internal buffer. So, calling it the next time would return
an empty string.
Sorry for the trouble.

Resources