mike chambers | about

Tutorial : Using JSON with Flex 2 and ActionScript 3

Tuesday, March 28, 2006

One of the little gems you will find in the open source ActionScript 3 libraries that we released on labs, is the JSON class found in the corelib library. This class, written for Adobe by Darron Schall, makes it super simple to both serialize and de-serialize JSON data.

What is JSON you ask? From the JSON website:

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

In a nutshell, JSON is a way to serialize data using JavaScript syntax. It is fairly compact, and easy to use. Furthermore, it has become increasingly popular due to the growth of AJAX applications, and the browser’s native support of de-serializing JSON (via eval()).

If you look on the main page of my weblog, the Reading / Doing section on the left is actually a small AJAX widget I created that shows my latests diggs, delicious bookmarks, and items added to my ta-da lists. It gets its data from a JSON feed on the server, which is periodically generated by a PHP file.

So, to show how to use JSON within a Flex / Flash application, we will load the JSON feed from my site into Flash and display it in a datagrid. Nothing earth shattering, but it will show how easy it is to use JSON. I am not assuming that you know anything about Flex / ActionScript or JSON. Because of this, the tutorial will be pretty long, as I want to make sure I cover every step of the process.

You can view the completed example here. (Requires Flash Player 8.5 beta 2).

First, you need to make sure you have the following installed:

You can grab Flex Builder and MXMLC from labs (the MXMLC compiler is included with the Flex Builder install, and also in the SDK download (in case you are on MAC or Linux).

Once you download the zip file for the corelib library, unzip it and you should see three subfolders: src, bins, docs.

You can link the project against either the source, or the SWC. For this example, we will use the SWC since we don’t need to edit the source code any.

Once Flex Builder is install, open it and make sure that you are in the Flex Development perspective.

Window > Open Perspective > Flex Development

Next, make sure the navigator view is open (it is usually on the left). This view shows all of your projects and files. If the view is not open, you can open it via:

Window > Show View > Navigator

Right click in the navigator and select:

New > Flex Project

Name the Project “JSONExample” and make sure “Use default location” is checked.

Then, click the “Next” button (not finish), this takes us to a screen that will allow us to add items to our class path, or to link against libraries. (you can access this at anytime, by selecting the project, and then selecting Project > Properties).

Select the Libraries tab, and click Add SWC. Browser to the corelib.swc file which was including in the bin directory of the corelib zip file. Click the Finish button.

The first thing we need to do is to add a datagrid to display the data. Our grid will contain two columns. One for the title, and one for the type of service (delicious, digg, tada).

Make sure that the JSONExample.mxml file is open in the editor (double click it in the Navigator), and then switch to design view (click the Design button in the top left of the editor). This brings us to design view which allows us to visually layout and manipulate our components.

Once you are in design view, you should see a Components view. If not, you can open it via Window > Show View > Components. This view contains all of the built in (and any custom components) that are available to the project. Select a DataGrid component from the Controls folder and drag it onto the stage. Once on the stage, resize it so that it takes up most of the space. The grid should snap to the edges when it gets close.

Make sure the grid is selected then go to the Flex Properties view. It should be open on the right, but if it isn’t you can open it via Window > Show Views > Flex Properties. We need to do two things here:

  1. Give the control an ID
  2. Set the layout constrains

Select the Id field at the top of the Flex Properties panel, and enter “grid”. This basically gives the grid a variable name so that other controls and ActionScript can reference it.

Next, scroll all the way to the bottom of the Flex Properties view to the Layout section. This will show your component with anchor points. Make sure that the following check boxes are checked:

This basically tells the controls to keeps its sides the same distance from the application’s sides, even if the app / windows resizes.

At this point, we are ready to switch back to source view, and load the JSON data. So, switch back to source view (click the Source button in the top left of the editor).

You code should now look something like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="absolute">
	<mx:DataGrid id="grid" right="10" left="10" top="10" bottom="10">
		<mx:columns>
			<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
			<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
			<mx:DataGridColumn headerText="Column 3" dataField="col3"/>
		</mx:columns>
	</mx:DataGrid>
</mx:Application>
</pre>

Lets add an HTTPService tag to actually load the data. Add the following tag right under the Application tag.

	<mx:HTTPService id="service" resultFormat="text" 
					url="http://weblogs.macromedia.com/mesh/mashedpotato.json"
					result="onJSONLoad(event)" />

If you save this, you should get an error in the problems view (Window > Show Views > Problems):

Call to a possibly undefined method 'onJSONLoad'`

This is ok. We just need to define the onJSONLoad event handler. But first, lets look at the code we just wrote:

At this point, your code should look something like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="absolute">

	<mx:HTTPService id="service" resultFormat="text" 
					url="http://weblogs.macromedia.com/mesh/mashedpotato.json"
					result="onJSONLoad(event)" />

	<mx:DataGrid id="grid" right="10" left="10" top="10" bottom="10">
		<mx:columns>
			<mx:DataGridColumn headerText="Column 1" dataField="col1"/>
			<mx:DataGridColumn headerText="Column 2" dataField="col2"/>
			<mx:DataGridColumn headerText="Column 3" dataField="col3"/>
		</mx:columns>
	</mx:DataGrid>
</mx:Application>

Next, we need to create a script block to define our event handler function. Add a Script tag block just below the Application tag:

	<mx:Script>
		<![CDATA[
			
		]]>
	</mx:Script>
</pre>

and then inside the Script block, lets define our event handler. You script block should now look like this:

	<mx:Script>
		<![CDATA[
			import mx.rpc.events.ResultEvent;
			
			private function onJSONLoad(event:ResultEvent):void
			{
			}
		]]>
	</mx:Script>

If you look at the API docs, ResultEvent is the type of event broadcast when the data has loaded from the service.

Next, all we need to do is:

Here is the completed function, with comments:

	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.rpc.events.ResultEvent;
			import com.adobe.serialization.json.JSON;
			
			private function onJSONLoad(event:ResultEvent):void
			{
				//get the raw JSON data and cast to String
				var rawData:String = String(event.result);
				
				//decode the data to ActionScript using the JSON API
				//in this case, the JSON data is a serialize Array of Objects.
				var arr:Array = (JSON.decode(rawData) as Array);
				
				//create a new ArrayCollection passing the de-serialized Array
				//ArrayCollections work better as DataProviders, as they can
				//be watched for changes.
				var dp:ArrayCollection = new ArrayCollection(arr);
				
				//pass the ArrayCollection to the DataGrid as its dataProvider.
				grid.dataProvider = dp;
				
			}
		]]>
	</mx:Script>

Notice that we also added some import statements to bring in the relevant classes.

The actual JSON de-serialization part is pretty trivial and consists of this one line of code:

var arr:Array = (JSON.decode(rawData) as Array);</pre>

JSON.decode returns a Object (since it doesn’t know before hand what it will be de-serializing), so we have to cast the result to an Array using the “as” operator. (can’t cast using Array() for legacy reasons).

At this point, we only have two things left to do:

  1. Actually tell the service to load the data.
  2. Customize the DataGrid to map to the data we are passing it.

Telling the service to load the data is easy. Since we want it to load the data as soon as the app loads, we can just specify in in the creationComplete event for the app (this is called once the app has been loaded and the controls laid out). (You can think of this as the same as onload in HTML / JavaScript).

We just need to add this attribute to the Application tag:

creationComplete="service.send()"</pre>

Remember that service is the id / variable name for our HTTPService control. Basically, this says when the app has loaded and initialized, tell the HTTPService control to load its data.

Finally, we need to tweak the DataGrid to show our data. In this case, we only need to tweak the columns within the DataGrid.

First, remove one of the three column tags, since we only need two.

Next, we need to add better column heading titles (through the headingText attribute), and map each column to a property in the data we loaded. If you look at the JSON data, you can see the following fields in each item:

For this example, we will just show the source and title. We specify this for each column through the dataField property. So, the new columns should look like this:

	<mx:DataGridColumn headerText="Service" dataField="src"/>
	<mx:DataGridColumn headerText="Title" dataField="title"/>

Basically, this tells the first column to use Service as the column title, and get its data from the “src” property of the loaded data. The second column gets it data from the title property.

The completed code should now look like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="absolute"
	creationComplete="service.send()">

	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.rpc.events.ResultEvent;
			import com.adobe.serialization.json.JSON;
			
			private function onJSONLoad(event:ResultEvent):void
			{
				//get the raw JSON data and cast to String
				var rawData:String = String(event.result);
				
				//decode the data to ActionScript using the JSON API
				//in this case, the JSON data is a serialize Array of Objects.
				var arr:Array = (JSON.decode(rawData) as Array);
				
				//create a new ArrayCollection passing the de-serialized Array
				//ArrayCollections work better as DataProviders, as they can
				//be watched for changes.
				var dp:ArrayCollection = new ArrayCollection(arr);
				
				//pass the ArrayCollection to the DataGrid as its dataProvider.
				grid.dataProvider = dp;
				
			}
		]]>
	</mx:Script>

	<mx:HTTPService id="service" resultFormat="text" 
					url="http://weblogs.macromedia.com/mesh/mashedpotato.json"
					result="onJSONLoad(event)" />

	<mx:DataGrid id="grid" right="10" left="10" top="10" bottom="10">
		<mx:columns>
			<mx:DataGridColumn headerText="Service" dataField="src"/>
			<mx:DataGridColumn headerText="Title" dataField="title"/>
		</mx:columns>
	</mx:DataGrid>
</mx:Application>

If you debug / run your app, you should see a datagrid that contains all of the data from the JSON feed. (You can debug by clicking the little Bug icon on the toolbar, or selecting Run > Debug).

If you are feeling generous, you can also easily publish your source code. Go back to Flex Builder, and select the JSONExample. Then select Project > Publish Application Source. Once you do this, re-run your application, and then right click on it and select View Source.

This is a pretty simple example, but it shows how easy de-serializing JSON in ActionScript is (serialization is just as easy).

Updated : You can also view a screencast of this tutorial.

Here are the links for the resources used in the tutorial:

I will update the post with images a little later, and am considering doing a screencast of building the example.

If you liked the tutorial, make sure to digg it.

Post any questions, suggestions and / or corrections in the comments.

twitter github flickr behance