Passing Data on Pop Methods in Mobile Flex
Posted on Oct 27, 2010
Within the world of mobile Flex development there is a concept of a ViewStack and navigator for handling navigating between views. It's a new concept in Flex but a relatively simple one to understand. Essentially you push a new View to the stack to have it displayed and you pop it out to go back in the stack. Passing data when you are pushing new views is extremely easy since the pushView() method takes a second argument that is an arbitrary data object. However, what isn't thoroughly obvious is how to pass data when you use either of the pop methods (popView() or popToFirstView()). In case you were wondering here's how (with kudos to my colleagues Stephen Gilson and Matt Horn for their help with this issue).
I created a simple mobile Flex application called PassingDataPop that has two Views. The first view contains a TextInput and a button that when pressed will send you to the second view while passing the contents of the TextInput as data to that view. We accomplish this simply using the pushView() method as follows:
protected function button1_clickHandler(event:MouseEvent):void
{
navigator.pushView(PassingDataPopPage2,{myValue:dataTxt.text});
}
In this case "PassingDataPopPage2" is the name of the mxml file for my second view and I am creating a structure of data with a property called "myValue" that contains whatever text is entered in my TextInput. To receive this data in my second View, I simply handle that on the View's viewActivate event as seen below in my viewActivate handler method:
protected function view1_viewActivateHandler(event:FlexEvent):void
{
dataTxt.text = data.myValue;
}
This method is simply setting the value of the TextInput on my second View to the "myValue" property passed in my data object. This is all pretty straightforward, but what happens with popView() and popToFirstView() which do not allow you to pass a data property. Let's look at the full code for my second view (PassingDataPopPage2.mxml):
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="PassingDataPopPage2" viewActivate="view1_viewActivateHandler(event)">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function view1_viewActivateHandler(event:FlexEvent):void
{
dataTxt.text = data.myValue;
}
override public function createReturnObject():Object {
var returnedObject:Object = new Object();
returnedObject.myValue = dataTxt.text;
return returnedObject;
}
protected function button1_clickHandler(event:MouseEvent):void
{
navigator.popView();
}
protected function button2_clickHandler(event:MouseEvent):void
{
navigator.popToFirstView();
}
]]>
</fx:Script>
<s:TextInput id="dataTxt" x="10" y="10" width="460" text="I am data."/>
<s:Button x="10" y="73" width="460" label="Pop Me or Click Back Button" click="button1_clickHandler(event)"/>
<s:Button x="10" y="156" width="460" label="Pop to First View" click="button2_clickHandler(event)"/>
</s:View>
You'll notice that I have a button that triggers popView() and another that triggers popToFirstView() (popView() is also triggered if you use the phone's built in back button). In order to pass data back, you'll see above those methods that I am overriding a method called createReturnObject() in the View class. The code for this is simply creating the same return object passed previously in my pushView() method. Both the popView() or the popToFirstView() calls will trigger this method.
Now that we know how to send the data, we need to look at how we receive this data. LEt's look at the full code for my Home view (PassingDataPopHome.mxml):
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Passing Data on Pop" viewActivate="view1_viewActivateHandler(event)">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function button1_clickHandler(event:MouseEvent):void
{
navigator.pushView(PassingDataPopPage2,{myValue:dataTxt.text});
}
protected function view1_viewActivateHandler(event:FlexEvent):void
{
if (returnedObject != null) {
dataTxt.text = returnedObject.myValue;
}
}
]]>
</fx:Script>
<s:TextInput id="dataTxt" x="10" y="10" width="460" text="I am data. Change me."/>
<s:Button x="10" y="73" width="460" label="Go To Next View" click="button1_clickHandler(event)"/>
</s:View>
You will see that in this View's viewActivate handler I am looking for a value called "returnedObject." Just like using the data object earlier, I simply refer to the myValue of thisobject and set the contents of the TextInput using that. Easy as pie once you know how to handle it.
Comments
If I wanted to pass in a static value such as an integer, how would you assign and pass that value in?
Can I assign the value of say '1' for the first button and how do I pass that in?
Something like below?
<s:button icon="@Embed('assets/pics/button.jpg')" click="navigator.pushView(New_View,{1:int}" />
Posted By matt / Posted on 02/01/2011 at 4:54 PM
At first glance that looks fine other than the fact that you have the key/value backwards. It would be pushView(New_View,{myval:1}) where myval is a key value equal to 1.
You can see my more extensive post covering passing data to views here http://www.remotesynthesis.com/post.cfm/passing-data-across-views-in-flex-mobile
Posted By Brian Rinaldi / Posted on 02/01/2011 at 5:59 PM
I can pass the data object between my views and then assign the value of the dataobject to a label text, but I can't for the life of my figure out how to assign the string value of the data object to a string variable in the second view using actionscript.
myLabel.text = {data}; that works, but I want to assign this value to another variable so I can use it in my actionscript logic for the view.
Right now I'm using a global variable to make this work, but I think this is too hacky and against best practices. This post seemed to be exactly what I needed, but I'm still having problems understanding what I'm doing wrong.
Thanks,
Andrew
Posted By Andrew / Posted on 08/31/2011 at 11:02 PM
Please note, the code in this post is from an earlier preview release of Flex. If you are passing data on pop, you need to look for navigator.poppedViewReturnedObject in your viewActivate handler. So something like this would work:
if (navigator.poppedViewReturnedObject != null) {
data = navigator.poppedViewReturnedObject;
}
This change was done so that when you pop to the prior view the state is returned exactly to how it was prior.
Posted By Brian Rinaldi / Posted on 09/01/2011 at 12:14 PM
After some intense step-debugging in the underlying Flex framework code, I've found that your update/comment isn't 100% accurate, Brian. The returned value does get exposed via that variable, but it is available in the creationComplete event handler, and is destroyed before the viewActivate event handler.
Posted By Adam Tuttle / Posted on 09/05/2011 at 8:58 PM
Adam Tuttle just saved what's left of my hair. Thank you.
Posted By RP / Posted on 02/06/2012 at 12:29 PM