<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Activetuts+ &#187; Flex</title>
	<atom:link href="http://active.tutsplus.com/category/tutorials/flex/feed/" rel="self" type="application/rss+xml" />
	<link>http://active.tutsplus.com</link>
	<description>Flash, Flex &#38; ActionScript Tutorials</description>
	<lastBuildDate>Mon, 15 Mar 2010 12:00:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Design a Panoramio Thumbnail Viewer in Flex</title>
		<link>http://active.tutsplus.com/tutorials/flex/design-a-panoramio-thumbnail-viewer-in-flex/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/design-a-panoramio-thumbnail-viewer-in-flex/#comments</comments>
		<pubDate>Wed, 09 Dec 2009 12:00:38 +0000</pubDate>
		<dc:creator>Matthew Casperson</dc:creator>
				<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=2669</guid>
		<description><![CDATA[<img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>During this tutorial I&#8217;ll take you through the ways in which Flex customizes interface controls. Specifically, we&#8217;ll be looking at the TileList element, styling it with Flex&#8217;s GUI toolkit.</p>
<p>To pull this all together, we&#8217;ll make use of the <a href="http://www.panoramio.com/api/" title="Panoramio API page">Panoramio API</a> and build a dynamic thumbnail image viewer.</p>
<p><span id="more-2669"></span></p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/PanoramioSource.zip" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/source.jpg" alt="" style="border:none"></a>
</div>
<h2>Quick Preview</h2>
<p>Here&#8217;s the thumbnail viewer we&#8217;re working towards:</p>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/Panoramio.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/Panoramio.swf" /></object>
</div>
<h2>Introduction</h2>
<p>Since the dawn of graphical operating systems there have been a handful of standard user interface controls like buttons, labels, text boxes and lists combo boxes. These controls have served their jobs well, but while Vista, Windows 7, MacOS, KDE and Gnome are bringing us fresh new visual designs, developers are quite often stuck designing their own applications with controls that haven’t changed their basic function in 20 years.</p>
<p>It doesn’t matter if you are making a web page, programming a Windows application with VB.Net or creating a RIA with Flex; when you get down to it a list is still a list, and a button is still a button.</p>
<p>Thankfully Flex offers developers a convenient way to customise the humble list, allowing for much more interesting designs than the standard lines of text. We will use this functionality to create a Panoramio image viewer.</p>
<h2>Step 1: Create a New Flex Project</h2>
<p>Create a new Flex project. Because we will be pulling photos from Panoramio (which returns a JSON object) we need to reference the AS3CoreLib library (which can convert JSON text to an ActionScript object), which you can download from <a href="http://code.google.com/p/as3corelib/">here</a>. Extract the archive and then add a reference to it in the &#8220;Flex Build Path&#8221;.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_91f653b3c4_b.png"></div>
<h2>Step 2: Define States</h2>
<p>Unlike desktop applications, Flex applications can only have the one window. States are used to easily change the controls on the screen when more than one display, like a thumbnail view and a detail view, is needed.</p>
<p>New states can be added using the &#8220;New State&#8221; button in the States toolbox.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_92gdmkwnp4_b.png"></div>
<p>We want to add two states. The first will be called &#8220;Thumbnails&#8221;. Click the &#8220;New State&#8221; button and fill out the dialog like the screenshot below. Notice that we tick &#8220;Set as start state&#8221;, which tells Flex that this is the state that will be first displayed.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_93g896rjgt_b.png"></div>
<p>We also need a state called &#8220;Detail&#8221;. Again, click the &#8220;New State&#8221; button and fill out the dialog like the screenshot below.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_94d2qwffgc_b.png"></div>
<h2> Step 3: Design the Thumbnail State</h2>
<p>Select the &#8220;Thumbnails&#8221; state from the States toolbox.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_95djfz3fgj_b.png"></div>
<p>Now paint a new TileList component onto the GUI. This component will be used to display the photo thumbnails.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_96gvxndpgt_b.png"></div>
<p>Assign the TileList an ID of &#8220;thumbnails&#8221; and set the &#8220;Data Provider&#8221; to <strong>{images}</strong>. Flex allows you to write ActionScript code within MXML element attributes by enclosing the code in curly braces, and we use that functionality here to set the images collection (which we will create later) as the source of the data for the TileList.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_104hkh48scf_b.png"></div>
<h2>Step 4: Design the Detail State</h2>
<p>Select the &#8220;Detail&#8221; state from the States toolbox.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_9784rr39hj_b.png"></div>
<p>Paint an Image control, with an id of &#8220;photo&#8221;, that takes up most of the screen space. Then down at the bottom add two Labels, with IDs of &#8220;photoTitle&#8221; and &#8220;photoLocation&#8221;, and a Button with a label of &#8220;Back&#8221;. </p>
<p>We also need to set the &#8220;On click&#8221; property of the Button to <strong>{this.currentState = &#8216;Thumbnails&#8217;}</strong>. Changing the value assigned to the &#8220;currentState&#8221; property is how we change between states in Flex, and just like with the &#8220;Data Provider&#8221; property of the TileList in step 3, we embed some ActionScript code into the attribute by enclosing it in curly braces. By assigning the string &#8220;Thumbnails&#8221; to the &#8220;currentState&#8221; property, we are instructing Flex to drop back to the Thumbnails state.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_106dw8djdgh_b.png"></div>
<p>Your final interface for the Detail state should look like the screenshot below.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_98gtckj2dp_b.png"></div>
<h2>Step 5: Create a New MXML Component </h2>
<p>MXML Components can be used to define how individual tiles are displayed within the TileList component. Click File &gt; New &gt; MXML Component.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_99ns56vz5d_b.png"></div>
<p>You will now see a dialog that allows you to specify the details for the MXML Component. Fill it out like the screenshot below.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_100dnj7mcf2_b.png"></div>
<p>When you are finished you will be taken to a design screen where you can paint components just like you would with the main Flex application.</p>
<h2>Step 6: Tile Layout</h2>
<p>This MXML Component will be used to draw the individual photos within the TileList. As you can see you have almost unlimited freedom in how the tiles are designed. Each tile can be designed with any Flex control in any layout you like.</p>
<p>The freedom to design each tile individually is what makes the TileList, and other controls like &#8220;DataGrid&#8221;, &#8220;HorizontalList&#8221;, &#8220;List&#8221;, &#8220;Menu&#8221; and &#8220;Tree&#8221; so powerful. In fact I have never seen any other GUI toolkit give developers this level of customisation without having to develop a new control from the ground up.</p>
<p>For our application we will display two components on each tile: an Image and a Label. The final layout should look something like the screenshot below.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_101f6b5xwc6_b.png"></div>
<h2>Step 7: Label</h2>
<p>Set the Text property for the Label to <strong>{data.photo_title.length &gt; 30 ? data.photo_title.substr(0, 27) + &#8216;&#8230;&#8217; : data.photo_title}</strong>. Here we display the &#8220;photo_title&#8221; property of the object that is bound to the component (we will see how this binding is done later) using a <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=03_Language_and_Syntax_14.html">ternary operator</a> (basically a shorthand if..else statement).</p>
<p>If it is 30 characters or less the full string will be displayed. Otherwise we display the first 27 characters followed by 3 periods to indicate that the title has been shortened.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_102njgczngx_b.png"></div>
<h2>Step 8: Image</h2>
<p>Set the &#8220;Source&#8221; property of the Image to <strong>{data.photo_file_url}</strong>. Again we are using ActionScript to pull out the &#8220;photo_file_url&#8221; property of the object that is bound to the component.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_103gx85zmgs_b.png"></div>
<h2>Step 9: Manually Specify MXML Attributes</h2>
<p>Go back to the main MXML file and switch the editor to the Source view.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_105m74sxp9s_b.png"></div>
<p>
    You should see a states element added to the Application element. This is the markup that represents the states we defined in step 2.</p>
<p>Under the states element there should be two State elements, and under each of them there will be AddChild elements. These relate to the components that we added to each state. </p>
<p>Under the State element with the &#8220;name&#8221; of &#8220;Thumbnails&#8221; you should see an AddChild element that contains a TileList element. This is the TileList that we added in step 3. We are going to have to add some the additional attributes below in order for the TileList to display our custom MXML Component.</p>
<pre name="code" class="xml">itemRenderer="ImageThumbnail" itemDoubleClick="photoSelected()" doubleClickEnabled="true"</pre>
<p>So the whole TileList element should read:</p>
<pre name="code" class="xml">&lt;mx:TileList itemRenderer="ImageThumbnail" itemDoubleClick="photoSelected()" doubleClickEnabled="true" dataProvider="{images}" id="thumbnails" bottom="0" top="0" left="0" right="0"/&gt;</pre>
<p>The &#8220;itemRenderer&#8221; attribute is the name of the MXML Component we created in step 5.</p>
<p>The &#8220;itemDoubleClick&#8221; attribute sets the &#8220;photoSelected&#8221; function to be called when an item is double-clicked.</p>
<p>The &#8220;doubleClickEnabled&#8221; attribute tells the component to treat two mouse clicks as a single double-click. Without this attribute the component would treat a double click as two single clicks, and the &#8220;itemDoubleClick&#8221; event would never be triggered.</p>
<h2>Step 10: Add a State Transition Effect</h2>
<p>Flex allows you to apply an effect when transitioning between one state and the next. We will use this functionality to initially blur the screen when changing between the Thumbnail and  Details states, then bring the screen back into focus.</p>
<p>To define state transistion we need to add a &#8220;transitions&#8221; element as a child of the MXML &#8220;Application&#8221; element.</p>
<pre name="code" class="javascript">&lt;mx:transitions&gt;
&lt;!-- Individual transitions go here --&gt;
&lt;/mx:transitions&gt;
</pre>
<p>Inside the transitions element we will add a Transition element.</p>
<pre name="code" class="javascript">&lt;mx:Transition fromState="*" toState="*"&gt;
&lt;!-- Transition effects go here --&gt;
&lt;/mx:Transition&gt;
</pre>
<p>The &#8220;fromState&#8221; and &#8220;toState&#8221; attributes define the states to which the transition will apply. Here we&#8217;ve used the asterisk as a wildcard, which matches all states, meaning that the transition effect will be applied when moving from any old state to any new state.</p>
<p>Inside the Transition element we define the effect istelf.</p>
<pre name="code" class="javascript">&lt;mx:Blur target="{this}" duration="500" blurYFrom="20.0" blurYTo="1.0" blurXFrom="20.0" blurXTo="1.0" /&gt;
</pre>
<p>The &#8220;target&#8221; attribute defines which component (and its children) will have the blur effect applied. In this case we want all the elements to be blurred, so we set the target to point to &#8220;this&#8221;.</p>
<p>The &#8220;duration&#8221; attribute defines how long to apply the blur effect for in milliseconds. We have used 500 here, which is half a second.</p>
<p>The &#8220;blurYFrom&#8221; and &#8220;blurXFrom&#8221; attributes define how blurry the effect will appear initially. Bigger values here make the initial effect more blurry.</p>
<p>The &#8220;blurYTo&#8221; and &#8220;blurXTo&#8221; attributes define how blurry the effect will be at the end of the duration. We want to bring the screen back into sharp focus, so we assign values of 1 to each of the attributes.</p>
<h2>Step 11: Retrieve the Images From Panoramio</h2>
<p>At this point we have defined our user interface. Now we need to get some images to display.</p>
<p>Add the following attribute to the Application element:</p>
<pre name="code" class="javascript">applicationComplete="appComplete()"</pre>
<p>This sets the &#8220;appComplete&#8221; function to be called when the application has initialised.</p>
<p>Add a &#8220;Script&#8221; element to the MXML Application element. This gives us a place to write the ActionScript code.</p>
<pre name="code" class="xml">&lt;mx:Script&gt;
&lt;![CDATA[

// Code goes here
]]&gt;
&lt;/mx:Script&gt;
</pre>
<p>In the Script element import the following packages.</p>
<pre name="code" class="javascript">import mx.collections.ArrayCollection;
import mx.controls.Alert;
import com.adobe.serialization.json.JSON;
</pre>
<h2>Step 12: Cross Domain Policy</h2>
<p>By default Flex will not allow you to load resources from an external domain. However, this behaviour can be overridden if the remote domain has a cross domain security policy file (usually crossdomain.XML). Fortunately Panoramio does have just such a policy file, which we load with the following code:</p>
<pre name="code" class="javascript">Security.loadPolicyFile("http://www.panoramio.com/crossdomain.xml");</pre>
<p>In step 3 we set the &#8220;Data Provider&#8221; property of the TileList to a collection called &#8220;images&#8221;. It is here that we actually define that collection. By using the &#8220;Bindable&#8221; tag on the variable we are telling Flex to watch for any changes to the collection, and to display those changes automatically.</p>
<pre name="code" class="javascript">[Bindable] private var images:ArrayCollection = null; </pre>
<h2>Step 13: appComplete Function</h2>
<p>Add a function called &#8220;appComplete&#8221;.</p>
<pre name="code" class="javascript">private function appComplete():void
{
	var panoramioURL:String = "http://www.panoramio.com/map/get_panoramas.php?order=popularity&amp;set=public&amp;from=0&amp;to=50&amp;minx=-180&amp;miny=-90&amp;maxx=180&amp;maxy=90&amp;size=medium";
	var request:URLRequest = new URLRequest(panoramioURL);
	var loader:URLLoader = new URLLoader(request);
	loader.addEventListener(Event.COMPLETE, loaderComplete);
	loader.addEventListener(
		IOErrorEvent.IO_ERROR,
		function(event:Event):void
		{
			Alert.show("There was an IO error contacting Panoramio");
		}
	);
	loader.addEventListener(
		SecurityErrorEvent.SECURITY_ERROR,
		function(event:Event):void
		{
			Alert.show("There was a security error contacting Panoramio");
		}
	);
}
</pre>
<p>
Getting images from Panoramio is actually very easy. Unlike other image-only sites like <a href="http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/">Flickr</a>, Panoramio doesn&#8217;t require the developer to get an API or or to use a special API. You simply make an HTTP request to a specially formatted URL (the <a href="http://www.panoramio.com/api/" title="Panoramio API page">Panoramio API page</a> has all the details) and use the returned JSON to get access to the images.</p>
<p>In Flex this means creating a &#8220;URLRequest&#8221; object with the Panoramio URL, then creating a new &#8220;URLLoader&#8221;, passing that request in the constructor. We then need to watch for 3 events from the URLLoader: <strong>Event.COMPLETE</strong>, <strong>IOErrorEvent.IO_ERROR</strong> and <strong>SecurityErrorEvent.SECURITY_ERROR</strong>. </p>
<p>The Event.COMPLETE event indicates that everything went well, and that the Panoramio server has returned the information we need. In this case we call the &#8220;loaderComplete&#8221; function. </p>
<p>The <strong>IOErrorEvent.IO_ERROR</strong> and <strong>SecurityErrorEvent.SECURITY_ERROR </strong>events indicate that something went wrong. In that case we notify the user that we could not contact the Panoramio server and don&#8217;t go any further.</p>
<h2>Step 14: loaderComplete Function</h2>
<p>Now add a new function called &#8220;loaderComplete&#8221;.</p>
<pre name="code" class="javascript">private function loaderComplete(event:Event):void
{
	var response:URLLoader = URLLoader(event.target);
	var responseData:Object = JSON.decode(response.data);

	this.images = new ArrayCollection();

	for each (var image:Object in responseData.photos)
	{
		this.images.addItem(image);
	}
}
</pre>
<p>Here we take the JSON returned by Panoramio and convert it into an ActionScript object using the AS3CoreLib library from step 1.</p>
<p>One of the tricks when working with web services in knowing what data has actually been actually returned. If you use Firefox there is a great add-on called <a href="https://addons.mozilla.org/en-US/firefox/addon/10122">JSONovich</a> which will format JSON code within the browser. In the screenshot below you can see the formatted JSON that was returned from the Panoramio web service. Notice that the JSON object has a property called &#8220;count&#8221; and an array called &#8220;photos&#8221; that contains the objects which in turn contain the details of the individual photos.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/033_panoramio/images/dq97m58_107f86kxxc4_b.png"></div>
<p>So, what we need to do is take each of the objects in this photos array and place them in our images collection. This is just a matter of looping through each of the objects in the photos collection and then calling &#8220;addItem&#8221; on the images collection.</p>
<p>Because the images collection had the &#8220;Bindable&#8221; tag, adding these objects into the collection will cause them to be displayed. If you look back to step 5 you will notice that the values for the Label and Image were set to properties from an object called &#8220;data&#8221;. This data object actually references an item in the images collection, and if you look at the screenshot above you can see where the photo_file_url and photo_title properties came from.</p>
<h2>Step 15: photoSelected Function</h2>
<p>The final function is called &#8220;photoSelected&#8221;.</p>
<pre name="code" class="javascript">private function photoSelected():void
{
	this.currentState = "Detail";

	var selectedPhoto:Object = this.thumbnails.selectedItem;

	this.photo.source = selectedPhoto.photo_file_url;
	this.photoTitle.text = selectedPhoto.photo_title;
	this.photoLocation.text = "Lat: " + selectedPhoto.latitude + " Long: " + selectedPhoto.longitude;
}
</pre>
<p>This function is called when the user double-clicks on a item in the TileList. Here we set the current state to &#8220;Detail&#8221;, and set the properties of the Image and Labels using the properties of the selected TileList item.</p>
<h2>Conclusion</h2>
<p>We have only just scratched the surface of what is possible with MXML Components, but hopefully you can see their potential. Being able to customise how a tile is drawn, without having to write any code, is just one of the many features that sets Flex apart from other development platforms.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/design-a-panoramio-thumbnail-viewer-in-flex/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Create a 3D Flickr Photo Gallery with Flex and Away3D</title>
		<link>http://active.tutsplus.com/tutorials/flex/creating-a-3d-flickr-photo-gallery-with-away3d/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/creating-a-3d-flickr-photo-gallery-with-away3d/#comments</comments>
		<pubDate>Fri, 30 Oct 2009 12:00:12 +0000</pubDate>
		<dc:creator>Matthew Casperson</dc:creator>
				<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=2340</guid>
		<description><![CDATA[<img src="http://activetuts.s3.cdn.plus.org/tuts/007_flickrGallery/preview_pumpkin.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>In this tut I&#8217;ll demonstrate how to build a dynamic photo gallery using the Flickr API. To add a little extra flair, we&#8217;ll harness the power of Away3D and display the photos in a 3D environment.</p>
<p>There&#8217;s plenty to discuss, so let&#8217;s get on with it!</p>
<p><span id="more-2340"></span></p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/007_flickrGallery/Flickr3DPhotosSource.zip" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/source.jpg" alt="" style="border:none"></a><br />
<a href="http://activetuts.s3.cdn.plus.org/tuts/007_flickrGallery/swf/preview.html" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Step 1: Reviewing the Flickr API</h2>
<p>This application will retrieve photos from Flickr to be displayed within a 3D space. Briefly, the process of downloading photos from Flickr is as follows:</p>
<ul>
<li>  A Flickr API key is obtained.</li>
<li>  The AS3Flickr and AS3CoreLib ActionScript libraries are downloaded and referenced from Flex Builder.</li>
<li>  The Flickr cross domain policy files are loaded to allow Flex to access images from remote domains.</li>
<li>  A search of Flickr is performed.</li>
<li>  The results are used to find the URL of the Flickr images.</li>
<li>  The images themselves are downloaded and saved/displayed.</li>
</ul>
<p>This process is covered in depth by a previous tutorial which you can find <a href="http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/">here</a>. I highly recommend you read that tutorial if you are not familiar with the AS3Flickr library, as these points will only be briefly mentioned in this tutorial.</p>
<h2>Step 2: An Introduction to Away3D Lite</h2>
<p>The Flash runtime has made some impressive progress over the last few years. The widespread deployment of the Flash runtime, both with Adobe AIR and browser plugins, along with the performance increase in later versions, means Flash has a very diverse ecosystem of libraries and applications. It has gone from being an animation tool to a general purpose development platform for games, business applications, 3D visualizations, video players and more.</p>
<p>3D engines have evolved alongside Flash for some time, going from a curiosity to now being fully featured and even commercial libraries. <a href="http://away3d.com/">Away3D</a> is one of the more popular free Flash 3D engines, and recently a smaller, faster version of Away3D was released called <a href="http://away3d.com/away3d-lite-v1-0-fastest-and-smallest-3d-engine-in-flash">Away3D Lite</a>. While Away3D Lite lacks some of the eye candy present in the more complicated 3D engines, its focus on simplicity means that it is perfect for a simple application like a 3D photo album.</p>
<h2>Step 3: Get Away3D Lite</h2>
<p>You can download a copy of Away3D Lite 1.0 for free from this web page <a href="http://www.brighthub.com/hubfolio/matthew-casperson/media/p/49050.aspx">here</a>. Download and extract the engine source code to a convenient location.</p>
<h2>Step 4: Get the Greensock TweenMax Library</h2>
<p>The movement of the camera within the 3D photo gallery will be performed using the Greensock <a href="http://blog.greensock.com/tweenmax/">TweenMax</a> library, which you can get from this page <a href="http://www.brighthub.com/hubfolio/matthew-casperson/media/p/54032.aspx">here</a>. Again, download and extract the library to a convenient location.</p>
<h2>Step 5: Get AS3Flickr and AS3CoreLib</h2>
<p>The AS3Flickr and AS3CoreLib libraries are used to contact the Flickr web service. You can find details about these libraries from the article<br />
<a href="http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/">Build a Photo Viewer Using Flex and the Flickr API</a>.
</p>
<h2>Step 6: Create a New Project</h2>
<p>Create a new Flex project, and add the Away3D Lite, TweenMax, AS3Flickr and AS3CoreLib libraries to the Flex Build Path.</p>
<div class="tutorial_image">  <img src="http://activetuts.s3.cdn.plus.org/tuts/007_flickrGallery/images/dq97m58_8355tqk7f4_b.png">
</div>
<h2>Step 7: Define the Application Attributes</h2>
<p><strong>applicationComplete=&#8221;appComplete()&#8221;</strong><br />
This sets the appComplete function to be called when the application has initialized, and will serve as the entry point for our code.</p>
<p><strong>frameRate=&#8221;100&#8243;</strong><br />
This sets the frame rate cap for the application at 100 frames per second. The default is 24, and increasing this will make the application seem more fluid.</p>
<p><strong>width=&#8221;600&#8243; height=&#8221;400&#8243; backgroundGradientAlphas=&#8221;[1.0, 1.0]&#8221; backgroundGradientColors=&#8221;[#000000, #374040]&#8220;</strong><br />
These attributes define the size and background color of the Flex application.</p>
<p>Your Application tag should look something like the code below:</p>
<pre name="code" class="xml">
  &lt;mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="absolute"
  applicationComplete="appComplete()"
  width="600"
  height="400"
  backgroundGradientAlphas="[1.0, 1.0]"
  backgroundGradientColors="[#000000, #374040]"
  frameRate="100"&gt;

  &lt;/mx:Application&gt;</pre>
<h2>Step 8: Add Some Controls</h2>
<p>Add the following tags to the Application tag.</p>
<pre name="code" class="xml">
&lt;mx:TextInput x="10" y="10" id="txtSearch"/&gt;
&lt;mx:Button x="178" y="10" label="Search" fillAlphas="[0.9, 0.9, 0.9, 0.9]" click="{applicationManager.flickrSearch(this.txtSearch.text)}"/&gt;
</pre>
<p>We&#8217;ll give the user the ability to search Flickr and display the results within our 3D photo gallery at run time. These two tags add a text box, where the search phrase can be entered, and a button to initiate the search.</p>
<p>The click event for the button calls <b>applicationManager.flickrSearch(this.txtSearch.text)</b>. The ApplicationManager will be created in later steps, and the flickrSearch function will contain the code to contact Flickr and download the photos.</p>
<h2>Step 9: Add Some Code</h2>
<p>Add a Script tag to the Application tag. This is where the ActionScript code will be written.</p>
<pre name="code" class="xml">&lt;mx:Script&gt;
&lt;![CDATA[
// code goes here
]]&gt;
&lt;/mx:Script&gt;
</pre>
<h2>Step 10: Add the Variables</h2>
<p>Add the following variable inside the Script tag.</p>
<pre name="code" class="javascript">private var applicationManager:ApplicationManager = null;</pre>
<p>The ApplicationManager class will be responsible for initializing the Away3D engine, loading the Flickr images and moving the camera. We hold a reference to it in the applicationManager variable so the button created in step 8 can call the flickrSearch function.</p>
<h2>Step 11: Loading the Cross Domain Policy Files</h2>
<pre name="code" class="javascript">
Security.loadPolicyFile("http://api.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm4.static.flickr.com/crossdomain.xml");
</pre>
<p>In order to access the images on the Flickr servers the cross domain policy files need to be loaded. This is covered in more detail in the article <a href="http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/" title="Build a Photo Viewer Using Flex and the Flickr API">Build a Photo Viewer Using Flex and the Flickr API</a>.</p>
<h2>Step 12: The appComplete Function</h2>
<p>Add a new function called appComplete.</p>
<pre name="code" class="javascript">
private function appComplete():void
{
applicationManager = new ApplicationManager();
this.addChildAt(new SpriteUIComponent(applicationManager), 0);
}</pre>
<p>This function is called when the Flex application has loaded and initialized. It is here that we create a new instance of the ApplicationManager class and add it as a child control. Notice that we actually pass an instance of a class called SpriteUIComponent to the addChildAt function.</p>
<p>As you will see in later steps, the ApplicationManager extends one of the template classes from the Away3D Lite API. These template classes themselves extend the Flex Sprite class. Even though the addChildAt function will accept a Sprite, an exception will be raised at runtime. This is because only classes extending the UIComponent class can be added a child controls of a Flex application. To work around this limitation the SpriteUIComponent extends the UIComponent class, and then adds a Sprite as its own child.</p>
<h2>Step 13: The SpriteUIComponent Class</h2>
<pre name="code" class="javascript">
package
{
    import flash.display.Sprite;

    import mx.core.UIComponent;

    public class SpriteUIComponent extends UIComponent
    {
        public function SpriteUIComponent(sprite:Sprite)
        {
            super ();

            explicitHeight = sprite.height;
            explicitWidth = sprite.width;

            addChild (sprite);
        }
    }
}</pre>
<p>As was mentioned above, the SpriteUIComponent class extends the UIComponent class (meaning it can be added as a child of a Flex application), and then adds the supplied Sprite object as its own child.</p>
<h2>Step 14: The ApplicationManager Class</h2>
<p>Import the following packages</p>
<pre name="code" class="javascript">
import away3dlite.core.base.*;
import away3dlite.core.utils.*;
import away3dlite.loaders.*;
import away3dlite.materials.*;
import away3dlite.primitives.*;
import away3dlite.templates.*;

import com.adobe.webapis.flickr.*;
import com.adobe.webapis.flickr.events.*;

import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;

import com.greensock.*;

import mx.collections.*;</pre>
<h2>Step 15: Extend the BasicTemplate</h2>
<p>Define the ApplicationManager class as extending the BasicTemplate class.</p>
<pre name="code" class="javascript">public class ApplicationManager extends BasicTemplate</pre>
<p>A new feature included with Away3D Lite are the template classes. Almost every Away3D application needs to initialize the same underlying classes like a camera and a view, and also setup event listeners for frame events. These common steps, which used to have to be coded by each developer manually, are now performed by one of several template classes. We will extend one of these template classes, BasicTemplate, with the ApplicationManager.</p>
<h2>Step 16: Define the Constants</h2>
<p>The ApplicationManager will have a number of constant variables that define the appearance and function of the class.</p>
<pre name="code" class="javascript">
private static const SEARCH_STRING:String = "landscape";
private static const MAX_RESULTS:int = 50;
private static const API_KEY:String = "YourFlickrAPIKey";
</pre>
<p>These three constants relate to the Flickr web service.</p>
<pre name="code" class="javascript">private static const PHOTO_HEIGHT:Number = 50;
private static const PHOTO_WIDTH:Number = PHOTO_HEIGHT * 1.618;</pre>
<p>These two variables define the size of the photos in 3D space. The width is defined relative to the height using the <a href="http://en.wikipedia.org/wiki/Golden_rectangle" title="golden rectangle">golden rectangle</a> ratio, which produces a rectangle whose shape is generally considered aesthetically pleasing.</p>
<pre name="code" class="javascript">private static const PHOTO_CLOUD_WIDTH:Number = 1000;
private static const PHOTO_CLOUD_HEIGHT:Number = 1000;
private static const PHOTO_CLOUD_DEPTH:Number = 3000;</pre>
<p>These three variables define the area that all the photos will be contained in.</p>
<pre name="code" class="javascript">private static const NUMBER_PHOTOS:int = 300;</pre>
<p>This variable defines how many individual photos will be created in the area defined above.</p>
<pre name="code" class="javascript">private static const CAMERA_JUMP_TIME:Number = 3;
private static const CAMERA_DIST_FROM_PHOTO:Number = 30;
private static const CAMERA_DIST_JUMP_BACK:Number = 100;</pre>
<p>These variables define the movement and speed of the camera as it jumps from one photo to the next. The camera will follow a bezier curve, with the start of the curve being 30 units back from a photo, moving towards a point 100 units back, and then ending at a point 30 units back from the next photo.&nbsp;</p>
<h2>Step 17: Embedding the Default Image</h2>
<pre name="code" class="javascript">[Embed(source="../media/texture.jpg")]
protected static const DefaultTexture:Class;</pre>
<p>The images that will be displayed all come from Flickr, which means that there will be an initial delay as the photos are retrieved. In the mean time an image embedded into the SWF file will be displayed, to give the user something to look at other than white rectangles.</p>
<h2>Step 18: Adding the Variables</h2>
<pre name="code" class="javascript">protected var textures:ArrayCollection = new ArrayCollection();
protected var photos:ArrayCollection = new ArrayCollection();
protected var loadedTextures:int = 0;</pre>
<p>The images returned from Flickr are stored in the textures collection. The Away3D Lite meshes that will display the images are stored in the photos collection. The loadedTextures variable keeps a track of how many images have been loaded from Flickr, so they can be stored in the appropriate position in the textures collection.</p>
<h2>Step 19: Initializing the ApplicationManager</h2>
<p>Add a new function called onInit.</p>
<pre name="code" class="javascript">override protected function onInit():void</pre>
<p>Once the underlying BasicTemplate object has initialized itself, the onInit function will be called. It is here that we initialize the extending class.</p>
<pre name="code" class="javascript">for (var i:int = 0; i &lt; MAX_RESULTS; ++i)
addTexture(Cast.bitmap(DefaultTexture)); </pre>
<p>First we create a collection of textures for our 3D photo meshes to use, all initially using the default image we embedded in step 17. Cast is a utility class provided by Away3D Lite, and here we use it to transform the embedded image into a BitmapData object, which is supplied to the addTexture function.</p>
<pre name="code" class="javascript">
for (var j:int = 0; j &lt; NUMBER_PHOTOS; ++j)
createPlane();
</pre>
<p>Now we create the meshes that will display the photo images. The 3D photos will in fact be planes: 2D rectangles with no depth that will face the camera.</p>
<pre name="code" class="javascript">flickrSearch(SEARCH_STRING);</pre>
<p>We then initiate a default search of the Flickr image database by calling flickrSearch, to give the user some images to look at before they perform their own search.</p>
<pre name="code" class="javascript">this.debug = false;</pre>
<p>The debug property of the BasicTemplate class is set to false, which turns off the default debug stats screen that is normally displayed with an Away3D Lite application.</p>
<pre name="code" class="javascript">this.camera.x = 0;
this.camera.y = 0;
this.camera.z = 10;
this.camera.lookAt(new Vector3D(0, 0, 0), new Vector3D(0, 1, 0));</pre>
<p>By default the BasicTemplate class places the camera down the negative end of the z axis, looking back towards the origin along a positive z axis. When the planes are created by the createPlane function, they are also created with their front pointing along the positive z axis. This means that the camera will, by default, be looking at the back face of the planes.</p>
<p>Typically in 3D applications polygons with their back to the camera are not visible (this is called back face culling), so to see the planes we need to move the camera up the positive end of the z axis and then look back at the origin along a negative z axis.</p>
<pre name="code" class="javascript">var randomPhoto:Mesh = photos.getItemAt(Math.random() * (MAX_RESULTS - 1)) as Mesh;</pre>
<p>We then get a reference to a random plane stored in the photos collection.</p>
<pre name="code" class="javascript">this.camera.x = randomPhoto.x;
this.camera.y = randomPhoto.y;
this.camera.z = randomPhoto.z + CAMERA_DIST_FROM_PHOTO;</pre>
<p>The camera is then position slightly in front of this random plane. This is the first photo the user will be looking at when the application loads.</p>
<pre name="code" class="javascript">bezierJump();</pre>
<p>Finally we start the TweenMax tweening operation that will move the camera from the current photo to view a new random photo.</p>
<h2>Step 20: The addTexture Function</h2>
<p>Add a new function called addTexture.</p>
<pre name="code" class="javascript">protected function addTexture(data:BitmapData):void
{
var texture:BitmapMaterial = new BitmapMaterial(data);
texture.smooth = true;
textures.addItem(texture);
}</pre>
<p>The addTexture function, called by onInit in step 19, creates a new BitmapMaterial class (which is the class that defines the texture of a 3D photos) using the supplied BitmapData, sets its smooth property to true, and adds it to the textures collection.</p>
<h2>Step 21: The createPlane Function</h2>
<p>Add a new function called createPlane.</p>
<pre name="code" class="javascript">protected function createPlane():void
{
	var mesh:Plane = new Plane(textures.getItemAt(Math.random() * (MAX_RESULTS - 1)) as BitmapMaterial,
    PHOTO_WIDTH,
    PHOTO_HEIGHT,
    1,
    1,
    false);

	mesh.x = Math.random() * PHOTO_CLOUD_WIDTH;
	mesh.y = Math.random() * PHOTO_CLOUD_HEIGHT;
	mesh.z = Math.random() * PHOTO_CLOUD_DEPTH;		

	scene.addChild(mesh);

	photos.addItem(mesh);
}</pre>
<p>The createPlane function, called by onInit in step 19, creates a new Plane using the dimensions defined by the constants in step 16 and textured with a random BitmapMaterial from the textures collection, positions them randomly within the &#8220;photo cloud&#8221; area, adds them to the scene (an Away3D object from the BasicTemplate class) so they are visible, and adds them to the photos collection so we can easily reference them later.</p>
<h2>Step 22: Getting Images from Flickr</h2>
<p>Add two new functions, one called flickrSearch and the other called onPhotosSearch.</p>
<pre name="code" class="javascript">public function flickrSearch(search:String):void
{
	var service:FlickrService = new FlickrService(API_KEY);
	service.addEventListener(FlickrResultEvent.PHOTOS_SEARCH, onPhotosSearch);
	service.photos.search("", search, "any", "", null, null, null, null, -1, "", MAX_RESULTS, 1);
}

protected function onPhotosSearch(event:FlickrResultEvent):void&nbsp;
{
	for each (var photo:Photo in event.data.photos.photos)
	{
		var imageURL:String = 'http://static.flickr.com/' +
        photo.server + '/' +
        photo.id + '_' +
        photo.secret + '_m.jpg';
		var loader:Loader = new Loader();
		loader.contentLoaderInfo.addEventListener(
			Event.COMPLETE,&nbsp;
			function(event:Event):void
			{
				var texture:BitmapMaterial = textures.getItemAt(loadedTextures) as BitmapMaterial;
				texture.bitmap = event.currentTarget.content.bitmapData;
				++loadedTextures;
				loadedTextures %= MAX_RESULTS;
			}
		);
		loader.load(new URLRequest(imageURL));
}
}</pre>
<p>Both these functions are taken almost line for line from <a href="http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/">Build a Photo Viewer Using Flex and the Flickr API</a>. The only difference is that as the images are loaded from Flickr their BitmapData is assigned to the bitmap property of the BitmapMaterial objects stored in the textures collection. This in turn changes the image that is displayed on the planes within the 3D scene.</p>
<p>In this way we can dynamically update the 3D photos being displayed with multiple calls to the flickrSearch function when the user does a search from the main GUI.</p>
<h2>Step 23: The bezierJump Function</h2>
<p>The bezierJump function is called repeatedly to jump the camera from one photo to the next.</p>
<pre name="code" class="javascript">protected function bezierJump():void</pre>
<p>Bezier curves are a convenient way to smoothly move the camera along curve defined by just 3 reference points: the cameras current position in front of a photo, a position behind the camera, and the final destination in front of a new photo.</p>
<pre name="code" class="javascript">var randomPhoto:Mesh = photos.getItemAt(Math.random() * (MAX_RESULTS - 1)) as Mesh;</pre>
<p>First a new random photo to move to is selected from the photos collection.</p>
<pre name="code" class="javascript">TweenMax.to(this.camera,CAMERA_JUMP_TIME,
{
	x: randomPhoto.x,
	y: randomPhoto.y,
	z: randomPhoto.z + CAMERA_DIST_FROM_PHOTO,</pre>
<p>We then use TweenMax to move the camera position (as defined by the x, y and z properties) to just in front of the position of the randomly selected destination photo&#8230;</p>
<pre name="code" class="javascript">delay: 2,</pre>
<p>after an initial delay of 2 seconds (which means the user views each photo for 2 seconds)&#8230;</p>
<pre name="code" class="javascript">bezier:&nbsp;
[{
	x: this.camera.x,
y: this.camera.y,
z: this.camera.z + CAMERA_DIST_JUMP_BACK
}],</pre>
<p>along a bezier curve that is influenced by a point just behind the cameras current position&#8230;</p>
<pre name="code" class="javascript">onComplete: bezierJump
});</pre>
<p>recursively calling the bezierJump function once the move is complete.</p>
<p>In this way the camera moves to a photo, views it for 2 seconds, jumps to the next photo and starts the process again. In general, recursively calling tweening functions is a great way to script movements in Flex applications.</p>
<h2>Conclusion</h2>
<p>I think you&#8217;ll agree that a 3D photo album is an eye catching way to display photos. Although we use publicly available Flickr images as the source of the photos here, this application could easily be modified to display your own images, either hosted on Flickr or downloaded from elsewhere.</p>
<p>I hope you liked this tutorial, thanks for reading!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/creating-a-3d-flickr-photo-gallery-with-away3d/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Control a Flex Video Application Using Mouse Gestures</title>
		<link>http://active.tutsplus.com/tutorials/flex/control-a-flex-video-application-using-mouse-gestures/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/control-a-flex-video-application-using-mouse-gestures/#comments</comments>
		<pubDate>Fri, 23 Oct 2009 12:00:00 +0000</pubDate>
		<dc:creator>Matthew Casperson</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Videos]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=2130</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/106_mouseGestures/demo/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Almost all PC user interfaces are designed around the notion of moving a cursor and clicking on  objects. Buttons, menus, combo boxes, lists and every other standard  UI control work in this way. The mouse is used to position the  cursor, and the position of the cursor is used to perform an action.</p>
<p>It’s a design paradigm that has worked well, but lately new  technologies like touch screens and motion sensors (think the Wii)  have challenged the notion of using a mouse, or even having a cursor  on the screen at all..</p>
<p><span id="more-2130"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/106_mouseGestures/src.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/106_mouseGestures/demo/mousegestures.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<p>Long before the focus on touch  screens or the Wii, programs like the Opera web browser introduced the  notion of mouse gestures. The concept was simple: instead of using  the position of the cursor to determine what action to perform, the  motion of the cursor itself would indicate an action. So by moving  the cursor in a circular motion you would trigger a web browser to  refresh. By moving it left you would go back in the page history, and  by moving it right you would move forward. </p>
<p>For Flash developers there&#8217;s a free  mouse gesture library that enables this type of interaction with very  little effort. To demonstrate how it&#8217;s used, we&#8217;ll create a simple  video player that uses mouse gestures, rather than buttons, to modify  the video playback.</p>
<h2>Step 1: Mouse Gesture Library</h2>
<p>Download Didier Brun&#8217;s mouse gesture library here  (<a href="http://www.brighthub.com/hubfolio/matthew-casperson/media/p/50540.aspx">http://www.brighthub.com/hubfolio/matthew-casperson/media/p/50540.aspx</a>),  and extract it to a convenient location.</p>
<h2>Step 2: New Application</h2>
<p>Create a new Flex web application and  add the mouse gesture library to the list of build paths. You can  access the build path property by selecting Project &gt; Properties &gt; Flex  Build Path within Flex Builder.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/106_mouseGestures/BuildPath.png" alt="" /></div>
<h2>Step 3: FLV</h2>
<p>You&#8217;ll need an FLV video file to test the application with. The demo version of the IMToo FLV converter  (<a href="http://www.imtoo.com/flv-converter.html">http://www.imtoo.com/flv-converter.html</a>)  will convert short videos from almost any format to FLV. If you don’t  have a collection of FLV movies lying around, this tool is ideal for  converting almost any free video you can download from the web. I  have converted one of the demo videos that ships with Vista for this  demo.</p>
<h2>Step 4: Application Attributes</h2>
<p>You will need to modify some of the  attributes of the Application element, contained in the MXML file.  Here we&#8217;ve specified the width, height, background color  (backgroundGradientColors) and transparency  (backgroundGradientAlphas). We&#8217;ve also set the appComplete function  to be called in response to the applicationComplete event. This gives  us an entry point in the application where the mouse gestures will be  set up.</p>
<pre name="code" class="xml">
&lt;mx:Application
 xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot;
 layout=&quot;absolute&quot;
 width=&quot;600&quot;
 height=&quot;400&quot;
 applicationComplete=&quot;appComplete()&quot;
 backgroundGradientAlphas=&quot;[1.0,  1.0]&quot;
 backgroundGradientColors=&quot;[#000000,  #000000]&quot;&gt;

&lt;/mx:Application&gt;
</pre>
<h2>Step 5: mx:VideoDisplay</h2>
<p>Add the following mx:VideoDisplay  element as a child of the mx:Application  element.</p>
<pre name="code" class="xml">
&lt;mx:VideoDisplay
 id=&quot;videoPlayer&quot;
 autoPlay=&quot;false&quot;
 bottom=&quot;30&quot;
 top=&quot;10&quot;
 left=&quot;10&quot;
 right=&quot;10&quot;
 source=&quot;Butterfly.flv&quot;
 metadataReceived=&quot;metadataReceived(event)&quot;
 playheadUpdate=&quot;playHeadUpdate(event)&quot;/&gt;
</pre>
<p>The id attribute assigns a name to the  VideoDisplay that we can reference from ActionScript.</p>
<p>The top, bottom, left and right  properties define the position of the VideoDisplay.</p>
<p>The autoPlay attribute is set to false,  which means the video will not start playing straight away. </p>
<p>The source attribute points to the  location of the video file. If you have your own FLV video file, then  you will need to modify this attribute to point to it. </p>
<p>The metadataReceived attribute points  to a function that will be called once the details of the video have  been loaded by the VideoDisplay. We use this to find out how long the  video is, so we can modify the maximum value of the HSlider.</p>
<p>The playheadUpdate attribute points to  a function that will be called as the video is played. This allows us  to track the current position of the video file, and update the  HSlider accordingly.</p>
<h2>Step 6: mx:HSlider</h2>
<p>Add the following mx:HSlider  element as a child of the mx:Application  Element</p>
<pre name="code" class="xml">
&lt;mx:HSlider
 id=&quot;videoPosition&quot;
 enabled=&quot;false&quot;
 bottom=&quot;10&quot;
 right=&quot;10&quot;
 left=&quot;10&quot;
 change=&quot;videoPositionChanged(event)&quot;/&gt;
</pre>
<p>The id attribute assigns a name to the  VideoDisplay that we can reference from ActionScript.</p>
<p>The top, bottom, left and right  properties define the position of the VideoDisplay.</p>
<p>The change attribute defines a function  to be called when the user changes the sliders position.</p>
<h2>Step 7: Interface</h2>
<p>You should now have a GUI that looks  like the one below.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/106_mouseGestures/GUI.png" alt="" /></div>
<h2>Step 8: mx:Script</h2>
<p>Add an mx:Script  element as a child of mx:Application.  This element will hold the ActionScript code for our application.</p>
<pre name="code" class="xml">
&lt;mx:Script&gt;
&lt;![CDATA[
 //  code goes here

]]&gt;
&lt;/mx:Script&gt;
</pre>
<h2>Step 9: Import Packages</h2>
<p>We need to import a number of packages.  This is done inside the mx:Script  element. Three classes from the mx.events package, MetadataEvent,  SliderEvent and  VideoEvent , are used as the parameters in event  listener functions. The com.foxaweb.ui.gesture package includes the  classes from the mouse gesture library.</p>
<pre name="code" class="xml">
import mx.events.MetadataEvent;
import mx.events.SliderEvent;
import mx.events.VideoEvent;
import com.foxaweb.ui.gesture.*;
</pre>
<h2>Step 10: Define Constants</h2>
<p>A number of constants are then defined.  The VIDEO_STEP constant defines how much time the video&#8217;s current  position will be moved by when we step forward or backward. The other  strings all define the names of actions that will be associated with  mouse gestures. In general it is prudent to map strings to constants  when they are used as an identification, as it allows the compiler to  pick up misspellings like <strong>if (action == SETP_FORWARD)</strong>, instead  of running into issues at runtime with misspelled strings like <strong>if  (action == &#8220;setp_forward&#8221;)</strong>.</p>
<pre name="code" class="xml">
private static const VIDEO_STEP:Number = 1;
private static const PLAY:String = &quot;play&quot;;
private static const STOP:String = &quot;stop&quot;;
private static const PAUSE:String = &quot;pause&quot;;
private static const STEP_FORWARD:String = &quot;step_forward&quot;;
private static const STEP_BACKWARD:String = &quot;step_backward&quot;;
</pre>
<h2>Step 11: Define Variables</h2>
<p>The last variable we need to define is  a reference to a MouseGesture object. It&#8217;s this object that implements the logic for the mouse gestures.</p>
<pre name="code" class="xml">
private var mg:MouseGesture = null;
</pre>
<h2>Step 12: New Function</h2>
<p>Add a new function called appComplete.  This is the function we assigned to the applicationComplete attribute  in the mx:Application  element. It is here that we will initialise the  mouse gestures.</p>
<pre name="code" class="javascript">
private function appComplete():void
{
 mg  = new MouseGesture(this.stage);
 mg.addGesture(PLAY,&quot;0&quot;);
 mg.addGesture(STOP,&quot;4&quot;);
 mg.addGesture(PAUSE,&quot;2&quot;);
 mg.addGesture(STEP_FORWARD,&quot;67012&quot;);
 mg.addGesture(STEP_BACKWARD,&quot;65432&quot;); 

 mg.addEventListener(GestureEvent.GESTURE_MATCH,matchHandler); 

}
</pre>
<h2>Step 13: Mouse Gestures</h2>
<p>First we create a new MouseGesture  object. The MouseGesture constructor needs to be passed a reference  to the stage in order to respond to mouse events.</p>
<pre name="code" class="javascript">
mg  = new MouseGesture(this.stage);
</pre>
<p>Next we define a number of mouse  gestures. A mouse gesture is defined as a sequence of mouse  movements, with numbers representing movement directions as per the  image below. All mouse gestures start by clicking the left mouse  button and end with the button being released.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/106_mouseGestures/gestures.png" alt="" /></div>
<p>For a simple gesture where the mouse is  moved in a straight line we use a string with a single number in it.  Here the &#8220;play&#8221; mouse gesture is defined as mouse movement in a  single direction, right, which is represented by the numeral 0.</p>
<pre name="code" class="javascript">
mg.addGesture(PLAY,&quot;0&quot;);
</pre>
<p>Likewise the &#8220;stop&#8221; and &#8220;pause&#8221;  mouse gestures are defined as mouse movements down and left.</p>
<pre name="code" class="javascript">
mg.addGesture(STOP,&quot;4&quot;);
mg.addGesture(PAUSE,&quot;2&quot;);
</pre>
<p>The &#8220;step_forward&#8221; mouse gesture is  more complex. It is defined as a half circle mouse movement, starting  at the left and then moving over and to the right. The red arrow  shows the start of the movement.</p>
<p>This movement is defined by the string  &#8220;67012&#8243;. You can see how this string is derived by matching the  movement of the mouse with the numbers that are assigned to those  movements. We start moving up (6), diagonally up and right (7), left  (0), diagonally down and right (1) and then down (2).</p>
<pre name="code" class="javascript">
mg.addGesture(STEP_FORWARD,&quot;67012&quot;);
</pre>
<p>The &#8220;step_backward&#8221; is defined in  the same way, only this time it is a half circle mouse movement,  starting at the right and then moving over and to the left.</p>
<pre name="code" class="javascript">mg.addGesture(STEP_BACKWARD,&quot;65432&quot;);</pre>
<p>We then assign the matchHandler  function to be called when a mouse gesture has been detected.</p>
<pre name="code" class="javascript">mg.addEventListener(GestureEvent.GESTURE_MATCH,matchHandler);</pre>
<h2>Step 14: The MatchHandler Function</h2>
<p>The matchHandler function is called  when a mouse gesture has been detected. The event parameter contains  a property called datas, which will match one of the constants we  assigned to the mouse events in the appComplete function. Depending  on the mouse gesture that has been detected we perform certain  actions on the VideoDisplay. The play, stop and pause actions are all  quite straight forward. With the step_forward and step_backward  actions we either increase or decrease the playheadTime property of  the VideoDisplay, which has the effect of skipping forward or  backward.</p>
<pre name="code" class="javascript">
private function matchHandler(event:GestureEvent):void
    {
        switch (event.datas)
            {
                case PLAY:
                    this.videoPlayer.play();
                    break;
                case STOP:
                    this.videoPlayer.stop();
                    break;
                case PAUSE:
                    this.videoPlayer.pause();
                    break;
                case STEP_FORWARD:
                    var newFowardTime:Number = this.videoPlayer.playheadTime  + VIDEO_STEP;
                    while (newFowardTime &gt; this.videoPlayer.totalTime)  newFowardTime = this.videoPlayer.totalTime;
                    this.videoPlayer.playheadTime  = newFowardTime;
                    break;
                case STEP_BACKWARD:
                    var newBackwardTime:Number = this.videoPlayer.playheadTime  - VIDEO_STEP;
                    if (newBackwardTime &lt; 0) newBackwardTime = 0;
                    this.videoPlayer.playheadTime  = newBackwardTime;
                break;
            }
        }

    }
    </pre>
<h2>Step 15: HSlider</h2>
<p>This demo is all about modifying the  video playback using mouse gestures, but for convenience a HSlider  can also be used. The metadataReceived  function is called once the  VideoDisplay has loaded the meta data, which includes the total  length of the video. In this function we set the maximum value of the  slider to the total length of the video. We then enable the slider –  until we know how long the video is the slider can’t be used to set  the position.</p>
<pre name="code" class="javascript">
private function metadataReceived(event:MetadataEvent):void
{
 this.videoPosition.maximum  = this.videoPlayer.totalTime;
 this.videoPosition.enabled  = true;
}
</pre>
<h2>Step 16: playHeadUpdate Function </h2>
<p>The position of the slider needs to be  kept in sync with the current play back position of the video. The  playHeadUpdate function is called at regular intervals by the  VideoDisplay, and it is here that we set the value of the HSlider to  the playheadTime of the VideoDisplay.</p>
<pre name="code" class="javascript">
private function playHeadUpdate(event:VideoEvent):void
{
 this.videoPosition.value  = event.playheadTime;
}
</pre>
<h2>Step 17: videoPositionChanged Function</h2>
<p>The slider can also be used to change  the current play back position of the video. Here we do the reverse  of the playHeadUpdate function, and set the playheadTime of the  VideoDisplay to the value of the HSlider.</p>
<pre name="code" class="javascript">
private function videoPositionChanged(event:SliderEvent):void
{
 this.videoPlayer.playheadTime  = this.videoPosition.value;
}
</pre>
<h2>Conclusion</h2>
<p>When you load up the application you  should see the video file. Because we set the autoPlay attribute of  the VideoDisplay object to false, the video will be stopped, showing the first frame.</p>
<p>Click the left mouse button, move the mouse  left and release the button, and the video should play. Click, move  the mouse down, and release, and the video should pause. Click, move  the mouse in a top half circle from left to right and release, and  you should see the video skip a second ahead.</p>
<p>Another benefit of mouse gestures is  that they remove the need for other UI controls, which can be a huge  advantage when screen space is at a minimum (like banner ads). You  could even use them for those &#8220;feed the monkey&#8221; or &#8220;do the most  chin-ups&#8221; banner ad games. </p>
<p>Mouse gestures are very easy to  implement in Flash, and they provide an intuitive way to interact  with a PC. With only a few lines of code you can redefine how users  interact with your application, and they free up the screen space  that was reserved for more traditional UI components. </p>
<p>Thanks for reading, I hope you learned something!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/control-a-flex-video-application-using-mouse-gestures/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Build a Photo Viewer Using Flex and the Flickr API</title>
		<link>http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 12:00:53 +0000</pubDate>
		<dc:creator>Matthew Casperson</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1918</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/092_Flickr/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>In this tutorial you will learn how to use the as3flickrlib library to create a Flash Flickr photo viewer.</p>
<p><span id="more-1918"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/092_Flickr/ImageFader.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/092_Flickr/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Step 1: The as3flickrlib</h2>
<p>There are many libraries available for Flex developers that interface with Flickr. The as3flickrlib library was created by Adobe and is the library that we&#8217;ll use to create this photo viewing application. You&#8217;ll need to download a copy of the as3flickrlib code for yourself, as well as the as3corelib library (as3flickrlib depends on as3corelib). Both can be obtained from <a href="http://labs.adobe.com/wiki/index.php/ActionScript_3:resources:apis:libraries">here</a>.</p>
<h2>Step 2: TweenMax</h2>
<p>You&#8217;ll also need the TweenMax library. TweenMax is a tweening library, which allows us to easily change the properties of an object over time. You can get TweenMax <a href="http://blog.greensock.com/tweenmaxas3/">here</a>.</p>
<h2>Step 3: New Project</h2>
<p>Create a new Flex web project and add the three libraries mentioned above to the Source Path of the application.</p>
<div class="tutorial_image"><img height="200" src="http://flashtuts.s3.cdn.plus.org/092_Flickr/step3.png" width="600" /></div>
<h2>Step 4: Wrapper Class</h2>
<p>This application works by taking the images loaded from Flickr and adding them to the main Application object (i.e. the object that is created by the MXML file). When you load an image off the web it is returned to you as a Bitmap. While the Bitmap class extends the DisplayObject class (which is what the addChild function requires), Flex will only allow those classes that extend the UIComponent class to be added as a child of the main Application object, and the Bitmap does not extend the UIComponent. The compiler will not flag adding a Bitmap to the Application object via the addChild function as an error, but you will get an exception at run time.</p>
<p>Still, it would be nice to be able to add the Bitmap objects as children of the Application object. We need to create a small wrapper class that does extend the UIComponent class (so it can be added to the Application), but also adds a Bitmap as a child of itself. That wrapper class is called DisplayObjectUIComponent.</p>
<pre name="code" class="javascript">
package
{
	import flash.display.DisplayObject;

	import mx.core.UIComponent;

	public class DisplayObjectUIComponent extends UIComponent
	{
		public function DisplayObjectUIComponent(displayObject:DisplayObject)
		{
		    super ();

		    explicitHeight = displayObject.height;
		    explicitWidth = displayObject.width;
		    addChild (displayObject);
		}
	}
}
</pre>
<h2>Step 5: New MXML File</h2>
<p>Now we need to create the MXML file. </p>
<pre name="code" class="javascript">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;mx:Application
  xmlns:mx=&quot;&lt;a href=&quot;http://www.adobe.com/2006/mxml&quot;&gt;http://www.adobe.com/2006/mxml&lt;/a&gt;&quot;
  layout=&quot;absolute&quot;
  backgroundGradientAlphas=&quot;[1.0, 1.0]&quot;
  backgroundGradientColors=&quot;[#000000, #5B5B5B]&quot;
  creationComplete=&quot;onComplete()&quot;&gt;

  ...

&lt;/mx:Application&gt;
</pre>
<p>This is the shell of the MXML file. Most of the code is the same as the empty template that is created when you open up a new Flex application in Flex Builder. In addition we&#8217;ve specified the background colors (with the <em>backgroundGradientAlphas</em> and <em>backgroundGradientColors</em> attributes) and set the onComplete function to be called when the Application object has created itself (with the <em>creationComplete</em> attribute).</p>
<h2>Step 6: mx:script Tag</h2>
<p>The code that will do the job of downloading and displaying the Flickr images needs to be contained in an mx:script tag. The &lt;![CDATA[ ... ]]&gt; tag just allows us to write code without having to worry about special characters like greater-than and less-than (&lt; and &gt;) being interpreted as part of the XML document.</p>
<pre name="code" class="javascript">
&lt;mx:Script&gt;
  &lt;![CDATA[

  ...

  ]]&gt;
&lt;/mx:Script&gt;
</pre>
<h2>Step 7: Import Classes</h2>
<p>We need to import some classes for use within our application.</p>
<pre name="code" class="javascript">
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import com.adobe.webapis.flickr.*;
import com.adobe.webapis.flickr.events.*;
import gs.TweenMax;
import gs.easing.*;
</pre>
<h2>Step 8: Define Constants</h2>
<p>Next we need to define some constants that will control how our application works.</p>
<pre name="code" class="javascript">
private static const SEARCH_STRING:String = "sunset";
private static const MAX_RESULTS:int = 50;
private static const API_KEY:String = "your key goes here";
private static const TRANSITION_TIME:Number = 1;
private static const DISPLAY_TIME:Number = 3;
</pre>
<ul>
<li>SEARCH_STRING defines the query that will be sent to Flickr. In essence we&#8217;ll be querying Flickr for images much like you would query Google for web pages. We have set the query to &quot;sunset&quot; here, but this string could be anything like &quot;kittens&quot;, &quot;mountains&quot;, &quot;cars&quot; etc.</li>
<li>MAX_RESULTS defines how many images Flickr will return once it has been queried.</li>
<li>API_KEY is your own Flickr API key, which you can apply for <a href="http://www.flickr.com/services/api/keys/apply/">here</a>.</li>
<li>TRANSITION_TIME defines how quickly the images will fade into each other in seconds. Here we&#8217;ve set the transition time to take 1 second.</li>
<li>DISPLAY_TIME defines how long each image will be displayed before the next image is loaded. Here we&#8217;ve set each image to be displayed for 3 seconds.</li>
</ul>
<h2>Step 9: Define Variables</h2>
<p>We need to define a few variables for our application.</p>
<pre name="code" class="javascript">
private var photos:ArrayCollection = null;
private var currentImage:int = 0;
private var displayImage:Bitmap = null;
private var backgroundImage:Bitmap = null;
</pre>
<ul>
<li>The photos variable is a collection of the photo definitions sent back by Flickr. It&#8217;s important to note that Flickr does not actually send back the photos themselves, but only the information needed to find the URL of the photo, which then has to be downloaded separately.</li>
<li>The currentImage variable maintains an index in the photos collection. This is so we know what photo needs to be displayed next.</li>
<li>The displayImage and backgroundImage variables are references to the Bitmap objects that are created by loading the Flickr images.</li>
</ul>
<h2>Step 10: Policy Files</h2>
<p>By default a Flash application can only load resources from it&#8217;s own domain. In order to load resources from another domain (like Flickr) the owner of that domain needs to have a policy file, usually called crossdomain.xml, that lets the Flash runtime know that it&#8217;s OK to load their resources. This policy file needs to be loaded before any attempts are made to load the resources.</p>
<p>Flickr hosts it&#8217;s images on a number of servers, so here we load the policy file of these servers. If you don&#8217;t perform this step you&#8217;ll get an exception when trying to load images off these domains.</p>
<pre name="code" class="javascript">
Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm4.static.flickr.com/crossdomain.xml");
</pre>
<h2>Step 11: onComplete Function</h2>
<p>When the Flex application has finished creating itself, the onComplete function will be called (this is what we specified in Step 5). The onComplete<br />
function is the entry point of the application.</p>
<pre name="code" class="javascript">
private function onComplete():void
{
	var service:FlickrService = new FlickrService(API_KEY);
	service.addEventListener(FlickrResultEvent.PHOTOS_SEARCH, onPhotosSearch);
	service.photos.search("", SEARCH_STRING, "any", "", null, null, null, null, -1, "", MAX_RESULTS, 1);
}
</pre>
<p>The first thing we need to do is create a new instance of the FlickrService class. The FlickrService object is our gateway to Flickr, and we use that to submit our search for our sunrise images. You need to supply the Flickr API key (from Step <img src='http://active.tutsplus.com/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> to the FlickrService constructor.</p>
<pre name="code" class="javascript">var service:FlickrService = new FlickrService(API_KEY);</pre>
<p>Next we attach a function to the FlickrResultEvent.PHOTOS_SEARCH event. This function will be called when Flickr has returned some information about a search. Here we attach the onPhotosSearch function.</p>
<pre name="code" class="javascript">service.addEventListener(FlickrResultEvent.PHOTOS_SEARCH, onPhotosSearch);</pre>
<p>Finally we perform the actual search itself. The search function has a lot of parameters that can be used to narrow a search down to a specific user, date, title and more. We&#8217;re only interested in finding photos with the tag sunset, and so supply either a null, empty string or -1 to these other parameters.</p>
<pre name="code" class="javascript">service.photos.search("", SEARCH_STRING, "any", "", null, null, null, null, -1, "", MAX_RESULTS, 1);</pre>
<h2>Step 12: onPhotoSearch Function</h2>
<p>The onPhotoSearch function is called when Flickr has returned some information about our search.</p>
<pre name="code" class="javascript">private function onPhotosSearch(event:FlickrResultEvent):void
{
	if (event.success)
	{
		var photoList:PagedPhotoList = event.data.photos;
		photos = new ArrayCollection( photoList.photos );
		loadNextImage();
	}
	else
	{
		Alert.show(&quot;Flickr call failed. Did you update the API Key?&quot;);
	}
}</pre>
<p>We first need to determine if the call to Flickr was successful. This is done by checking the event.success flag. If this is true Flickr has successfully returned some information about the photos we queried it for. If event.success is false then the call failed. This usually happens because the API key that was supplied was incorrect.</p>
<pre name="code" class="javascript">
if (event.success)
{
	...
}
else
{
	...
}
</pre>
<p>If the call was successful we need to get access to the collection of photo data that was returned.</p>
<pre name="code" class="javascript">var photoList:PagedPhotoList = event.data.photos;</pre>
<p>The PagedPhotoList then contains the details of the photos themselves, which we then save in the photos collection.</p>
<pre name="code" class="javascript">photos = new ArrayCollection( photoList.photos );</pre>
<p>At this point the photos collection contains a list of photo details which can then be used to load the actual photo images. From here on in we&#8217;ll just be downloading images, from the URLs we created using the information in the photos collection, without any more special calls using the Flickr API.</p>
<p>To start the photo album, we need to call the loadNextImage function.</p>
<pre name="code" class="javascript">loadNextImage();</pre>
<p>If there was a problem calling Flickr the user is notified with an Alert window.</p>
<pre name="code" class="javascript">Alert.show(&quot;Flickr call failed. Did you update the API Key?&quot;);</pre>
<h2>Step 13: loadNextImage Function</h2>
<p>Now that we have the details of the photos that relate to our search, we need to actually download the images so they can be displayed. This is done by the loadNextImage function.</p>
<pre name="code" class="javascript">
private function loadNextImage():void
{
	var imageURL:String = 'http://static.flickr.com/' + photos[currentImage].server + '/' + photos[currentImage].id + '_' + photos[currentImage].secret + '_m.jpg';

	++currentImage;
	currentImage %= photos.length;

	var request:URLRequest = new URLRequest(imageURL);
	var loader:Loader = new Loader();
	loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchImages);

	loader.load(request);
}</pre>
<p>Remember that I said that the call to Flickr does not actually return the images themselves? What it does return is the information needed to<br />
construct the URL that we can use to download the image. By using the server, id and secret information of the photos we can create the full URL that will display the image.</p>
<p>Each image has a number of resolutions. We pick which size image we are downloading by the suffix of the url. The _m suffix indicates that we are<br />
downloading a medium sized version of the image. Other suffixes can be found <a href="http://www.flickr.com/services/api/misc.urls.html">here</a>, which allows you to download more or less detailed versions of the images.</p>
<pre name="code" class="javascript">var imageURL:String = 'http://static.flickr.com/' + photos[currentImage].server + '/' + photos[currentImage].id + '_' + photos[currentImage].secret + '_m.jpg';</pre>
<p>Now that we&#8217;ve requested the image, we increment the currentImage variable so the next time loadNextImage is called we&#8217;ll pull down the next image in the search list.</p>
<pre name="code" class="javascript">++currentImage;
currentImage %= photos.length;</pre>
<p>Next we have to actually load the images. We create a new URLRequest object (supplying the URL that we created above to the constructor), a new Loader object, and attach the switchImages function to the Loaders Event.COMPLETE event.</p>
<pre name="code" class="javascript">var request:URLRequest = new URLRequest(imageURL);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchImages);</pre>
<p>Finally, we load the image from Flickr by calling the Loaders load function.</p>
<pre name="code" class="javascript">loader.load(request); </pre>
<h2>Step 14: switchImages Function</h2>
<p>The switchImages function is called when we&#8217;ve loaded an new image from Flickr.</p>
<pre name="code" class="javascript">private function switchImages(event:Event):void
{
	displayImage = event.currentTarget.content;
	displayImage.smoothing = true;
	displayImage.width = this.width;
	displayImage.height = this.height;
	displayImage.alpha = 0;
	this.addChild(new DisplayObjectUIComponent(displayImage));

	TweenMax.to(displayImage, TRANSITION_TIME, {alpha:1, ease:Linear, onComplete:imageTweenComplete});
	if (backgroundImage != null)
		TweenMax.to(backgroundImage, TRANSITION_TIME, {alpha:0, ease:Linear});
}</pre>
<p>The Bitmap object that is returned by the loading process is saved in the displayImage variable.</p>
<pre name="code" class="javascript">displayImage = event.currentTarget.content;</pre>
<p>This new Bitmap is then initialized so that it is smoothed (to help with the pixelization that can occur when you scale up small images), resized to fill the window, and set to be completely transparent by setting it&#8217;s alpha to 0.</p>
<pre name="code" class="javascript">displayImage.smoothing = true;
displayImage.width = this.width;
displayImage.height = this.height;
displayImage.alpha = 0;</pre>
<p>We then add the Bitmap to the Application via a new instance of the DisplayObjectUIComponent class that we described in Step 4.</p>
<pre name="code" class="javascript"> this.addChild(new DisplayObjectUIComponent(displayImage));</pre>
<p>At this point we have the new image added as a child of the Application object. It isn&#8217;t visible though because we&#8217;ve set the alpha to 0. What we want to do is fade this new image into view by increasing it&#8217;s alpha value, while at the same time fading out the last image by decreasing it&#8217;s alpha value. This is where the TweenMax library comes in. We make a call to the TweenMax.to function, and TweenMax then takes care of modifing the alpha values for us.</p>
<p>By setting the onComplete parameter to imageTweenComplete we schedule the imageTweenComplete function to be called once this tweening operation is<br />
compete.</p>
<p>We do need to check if the backgroundImage variable is null because when the first image is loaded there is no existing backgroundImage that it is displaying on top of.</p>
<pre name="code" class="javascript">TweenMax.to(displayImage, TRANSITION_TIME, {alpha:1, ease:Linear, onComplete:imageTweenComplete});
if (backgroundImage != null)
	TweenMax.to(backgroundImage, TRANSITION_TIME, {alpha:0, ease:Linear});</pre>
<h2>Step 15: imageTweenComplete Function</h2>
<p>The imageTweenComplete function is called when a newly loaded image has been faded into view by TweenMax.</p>
<pre name="code" class="javascript">private function imageTweenComplete():void
{
	if (backgroundImage != null)
	this.removeChild(backgroundImage.parent);
	backgroundImage = displayImage;
	displayImage = null;

	TweenMax.delayedCall(DISPLAY_TIME, loadNextImage);
}</pre>
<p>Once the displayImage has been faded in, the backgroundImage is removed from the application and the displayImage becomes the backgroundImage. The<br />
displayImage is then set to null.</p>
<pre name="code" class="javascript">if (backgroundImage != null)
	this.removeChild(backgroundImage.parent);
backgroundImage = displayImage;
displayImage = null;</pre>
<p>We then use TweenMax to schedule a call to the loadNextImage function. This starts the cycle of loading a new image and fading it in again.</p>
<pre name="code" class="javascript">TweenMax.delayedCall(DISPLAY_TIME, loadNextImage);</pre>
<h2>Conclusion</h2>
<p>Using Flickr with Flash does require a few steps, but once you get your head around the Flickr API, finding out the Flickr image URLs, loading the images from Flickr (taking the Flash security restrictions into consideration) it&#8217;s then quite easy to use these images to create an appealing photo album.</p>
<p>This particular example could be used to add an animated photo album to a web page, and by changing the SEARCH_STRING variable you can display different types of images. You could even pass FlashVars to the Flash applet to determine which images are displayed without having to recompile the application. You could also modify the service.photos.search function to return only your own photos, or those that you have tagged specifically.</p>
<p>Thanks for reading.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Working with the Flex DataGrid and Nested Data Structures</title>
		<link>http://active.tutsplus.com/tutorials/flex/working-with-the-flex-datagrid-and-nested-data-structures/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/working-with-the-flex-datagrid-and-nested-data-structures/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 12:00:52 +0000</pubDate>
		<dc:creator>Anand</dc:creator>
				<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1892</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/Preview/200x200.png" alt="">]]></description>
			<content:encoded><![CDATA[<p>It often happens that the data which needs to be viewed/presented in a Flex DataGrid comes from an XML file or JSON with more than one level of nesting. Unfortunately, by default, the Flex DataGrid allows you to display only single level nested object arrays.</p>
<p>This tutorial shows how you can extend the Flex DataGrid class to accomodate more complicated data structures. It will also show you how to make all the columns sortable, even when using nested data structures.</p>
<p><span id="more-1892"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/code.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/Preview/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Introduction</h2>
<p> This tutorial assumes that you know the basics of Flex, how to use Flex Builder, and how to write MXML files. You should have a copy of Flex Builder installed on your system.
</p>
<h2>Step 1: Setup the Flex Project</h2>
<p>
The first step is to setup the project in Flex Builder. Create a new project in Flex Builder with <em>Project Name</em> as &#8220;NestedDataGrid&#8221; and <em>Application Type</em> as &#8220;Web application (runs in Flash Player)&#8221;. Leave all other options at their default values and click Finish.
</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/Tutorial/1.png" alt="Creating the new project" /></div>
<h2>Step 2: Import Sample Data</h2>
<p>The data that we&#8217;re going to show in the DataGrid is obtained from an XML file. Create a folder in your &#8217;src&#8217; folder called &#8216;assets&#8217; and put the data shown below in a file called &#8216;meetings.xml&#8217;. Alternatively, you can download the XML file from <a href='http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/meetings.zip'>here</a> and put it in the &#8216;assets&#8217; folder.</p>
<pre name="code" class="xml">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;meetings&gt;
  &lt;meeting&gt;
    &lt;priority&gt;high&lt;/priority&gt;
    &lt;presenter&gt;
      &lt;name&gt;Lisa Green&lt;/name&gt;
      &lt;email&gt;jdoe@company.com&lt;/email&gt;
      &lt;phone&gt;+330-7593&lt;/phone&gt;
    &lt;/presenter&gt;
    &lt;date&gt;12th July 2009&lt;/date&gt;
    &lt;time&gt;6:00 pm&lt;/time&gt;
    &lt;place&gt;Room 405&lt;/place&gt;
  &lt;/meeting&gt;
  &lt;meeting&gt;
    &lt;priority&gt;medium&lt;/priority&gt;
    &lt;presenter&gt;
      &lt;name&gt;Christopher Martin&lt;/name&gt;
      &lt;email&gt;cmartin@company.com&lt;/email&gt;
      &lt;phone&gt;+330-7553&lt;/phone&gt;
    &lt;/presenter&gt;
    &lt;date&gt;14th July 2009&lt;/date&gt;
    &lt;time&gt;11:00 am&lt;/time&gt;
    &lt;place&gt;Room 405&lt;/place&gt;
  &lt;/meeting&gt;
  &lt;meeting&gt;
    &lt;priority&gt;high&lt;/priority&gt;
    &lt;presenter&gt;
      &lt;name&gt;George Rodriguez&lt;/name&gt;
      &lt;email&gt;grodriguez@company.com&lt;/email&gt;
      &lt;phone&gt;+330-7502&lt;/phone&gt;
    &lt;/presenter&gt;
    &lt;date&gt;18th July 2009&lt;/date&gt;
    &lt;time&gt;10:00 am&lt;/time&gt;
    &lt;place&gt;Room 771&lt;/place&gt;
  &lt;/meeting&gt;
  &lt;meeting&gt;
    &lt;priority&gt;high&lt;/priority&gt;
    &lt;presenter&gt;
      &lt;name&gt;Jennifer Parker&lt;/name&gt;
      &lt;email&gt;jparker@company.com&lt;/email&gt;
      &lt;phone&gt;+330-5380&lt;/phone&gt;
    &lt;/presenter&gt;
    &lt;date&gt;20th August 2009&lt;/date&gt;
    &lt;time&gt;2:00 pm&lt;/time&gt;
    &lt;place&gt;Room 562&lt;/place&gt;
  &lt;/meeting&gt;
&lt;/meetings&gt;
</pre>
<h2>Step 3: Make the Interface</h2>
<p>Here&#8217;s a quick breakdown of building the interface to display the data and the appropriate ID values required for the code in this tutorial:</p>
<ol>
<li>Open the NestedDataGrid.mxml file, and go to the design view</li>
<li>Drag and drop a &#8216;Panel&#8217; from the Components view. Set its ID to &#8220;meetingsPanel&#8221; and Title to &#8220;Meetings&#8221;</li>
<li>Set the height and width of the Panel to 500 and set the X and Y values to 0</li>
<li>Drag and drop a &#8216;DataGrid&#8217; onto the panel</li>
<li>Set the X and Y values to 10</li>
<li>Set the width to {meetingsPanel.width-40} and height to 45%</li>
<li>Go to the source view, and in the &#8216;mx:Appication&#8217; tag, add the attribute layout=&#8221;vertical&#8221;</li>
</ol>
<p>Your interface should look similar to that shown in the image below:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/Tutorial/2.png" alt="The interface" /></div>
<p>The MXML in the source view should look like this:</p>
<pre name="code" class="xml">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"&gt;
  &lt;mx:Panel x="0" y="0" width="500" height="500" layout="absolute" id="meetingsPanel" title="Meetings"&gt;
    &lt;mx:DataGrid x="10" y="10" width="{meetingsPanel.width-40}" height="45%"&gt;
      &lt;mx:columns&gt;
        &lt;mx:DataGridColumn headerText="Column 1" dataField="col1"/&gt;
        &lt;mx:DataGridColumn headerText="Column 2" dataField="col2"/&gt;
        &lt;mx:DataGridColumn headerText="Column 3" dataField="col3"/&gt;
      &lt;/mx:columns&gt;
    &lt;/mx:DataGrid&gt;
  &lt;/mx:Panel&gt;
&lt;/mx:Application&gt;
</pre>
<h2>Reading in the XML File</h2>
<p>In the next three steps, we create an HTTPService component, read the data from the XML file and store it in a local variable. This is done in three stages:</p>
<h2>Step 4: Create the HTTPService Component</h2>
<p>Switch to the Source view of the MXML file and add the following code right below the <em>mx:Application</em> tag:
    </p>
<pre name="code" class="xml">
    &lt;mx:HTTPService id="readXML"
      url="assets/meetings.xml" resultFormat="object"
      result="httpResultHandler(event)" fault="httpFaultHandler(event)" /&gt;
    </pre>
<p>
  The httpResultHandler() function will be called when the data has been fetched. If there&#8217;s an error in fetching the data, the httpFaultHandler() function is called. Note that this only creates the HTTPService object, the data has to be fetched by an explicit function call (See sub-step 3)
    </p>
<h2>Step 5: httpResultHandler() and httpFaultHandler()</h2>
<p>Add an <em>mx:Script</em> tag just below the <em>mx:Application</em> tag. Inside that, define the variable that will hold the incoming data and the functions to handle the events from the HTTPService component. The code to do that looks like this:
  </p>
<pre name="code" class="java">
      import mx.rpc.events.FaultEvent;
      import mx.rpc.events.ResultEvent;
      import mx.collections.ArrayCollection;
      import mx.controls.Alert;

      [Bindable]
      public var dataForGrid:ArrayCollection;

      private function httpResultHandler(event:ResultEvent):void{
        dataForGrid = event.result.meetings.meeting;
      }

      private function httpFaultHandler(event:FaultEvent):void{
        Alert.show("Error occurred in getting string");
      }
   </pre>
<p>The  variable &#8216;dataForGrid&#8217; holds the data that we are going to read in. The &#8216;[Bindable]&#8216; tag makes sure that whenever the data changes (when it is read in), the DataGrid is updated accordingly. The XML is read in as an object which is passed throught the &#8216;ResultEvent&#8217; event, and &#8216;event.result.meetings.meeting&#8217; accesses the ArrayCollection of &#8216;meeting&#8217; objects.
   </p>
<h2>Step 6: Get the Data From the XML File</h2>
<p>In this step, the actual function call to get the XML data is done. An intialize function is assigned to the event that is triggered everytime the application loads &#8211; the &#8216;creationComplete&#8217; event. Add the attribute <em>creationComplete=&#8221;getData()&#8221;</em> to the &#8216;mx:Application&#8217; tag and define the function &#8216;getData()&#8217; as below (to be added after the &#8216;httpFaultHandler&#8217; function):</p>
<pre name="code" class="java">
      private function getData():void{
        readXML.send();
      }
  </pre>
<p>This makes the HTTPService object get the data from the file. Once the data is retrieved, the &#8216;result&#8217; event is triggered which calls the &#8216;httpResultHandler()&#8217; function. If there&#8217;s a problem getting the data, the &#8216;fault&#8217; event is triggered, which calls the httpFaultHandler() function.</p>
<h2>Step 7: Milestone</h2>
<p>At this point your NestedDataGrid.mxml should look like this:</p>
<pre name="code" class="xml">
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="getData()"&gt;
&lt;mx:Script&gt;
  &lt;![CDATA[
      import mx.rpc.events.FaultEvent;
      import mx.rpc.events.ResultEvent;
      import mx.collections.ArrayCollection;
      import mx.controls.Alert;

      [Bindable]
      public var dataForGrid:ArrayCollection;

      private function httpResultHandler(event:ResultEvent):void{
        dataForGrid = new ArrayCollection(event.result.meetings.meeting);
      }

      private function httpFaultHandler(event:FaultEvent):void{
        Alert.show("Error occurred in getting string");
      }

      private function getData():void{
        readXML.send();
      }

  ]]&gt;
&lt;/mx:Script&gt;
    &lt;mx:HTTPService id="readXML"
      url="assets/meetings.xml" resultFormat="object"
      result="httpResultHandler(event)" fault="httpFaultHandler(event)" /&gt;
  &lt;mx:Panel width="500" height="500" layout="vertical" id="meetingsPanel" title="Meetings"&gt;
    &lt;mx:DataGrid width="{meetingsPanel.width-40}" height="45%"&gt;
      &lt;mx:columns&gt;
        &lt;mx:DataGridColumn headerText="Column 1" dataField="col1"/&gt;
        &lt;mx:DataGridColumn headerText="Column 2" dataField="col2"/&gt;
        &lt;mx:DataGridColumn headerText="Column 3" dataField="col3"/&gt;
      &lt;/mx:columns&gt;
    &lt;/mx:DataGrid&gt;
  &lt;/mx:Panel&gt;
&lt;/mx:Application&gt;
</pre>
<h2>Step 8: DataGrid with Non-Nested Data</h2>
<p>I&#8217;ll just briefly point out why nested data poses problems in display, by first demonstrating how you show non-nested data. Say, from the XML file above, you only wanted to show the date, place and priority of the meetings (and not the presenter information). The below code will be able to display it without any problems (contents of &#8216;mx:Panel&#8217; shown here. All other code is the same):
</p>
<pre name="code" class="xml">
    &lt;mx:DataGrid width="{meetingsPanel.width-40}" height="45%" dataProvider="{dataForGrid}"&gt;
      &lt;mx:columns&gt;
        &lt;mx:DataGridColumn headerText="Priority" dataField="priority"/&gt;
        &lt;mx:DataGridColumn headerText="Date" dataField="date"/&gt;
        &lt;mx:DataGridColumn headerText="Time" dataField="time"/&gt;
        &lt;mx:DataGridColumn headerText="Place" dataField="place"/&gt;
      &lt;/mx:columns&gt;
    &lt;/mx:DataGrid&gt;
</pre>
<p>The result of the this would be the following application:</p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/Preview/preview_non_nested.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/milestone.jpg" alt="" style="border:none"></a>
</div>
</p>
<p>Note that the dataProvider attribute of the DataGrid can be directly assigned to the the ArrayCollection &#8216;dataForGrid&#8217;, and each DataGridColumn inside is given a dataField attribute that directly corresponds to the property name. However, suppose you want to access the presenter&#8217;s name information, it can be accessed as &#8220;presenter.name&#8221;. If you try giving this value to the &#8216;dataField&#8217; you&#8217;ll get an error. This is because, Flex doesn&#8217;t support nested objects by default. Read on to learn how to solve this problem by extending the DataGridColumn class and writing your own code to handle this case.
</p>
<h2>Step 9: Creating the NestedDataGridColumn Class</h2>
<p>We redefine some functions in the DataGrid column class to circumvent the problem outlined above. First create a folder in the &#8217;src&#8217; directory called &#8216;classes&#8217;. Create a new &#8216;ActionScript Class&#8217; in that folder, named &#8220;NestedDataGridColumn&#8221;. In the &#8216;Superclass&#8217; field, click &#8216;Browse&#8230;&#8217; and select &#8216;DataGridColumn&#8217; from the list that pops up. Leave everything else at the default values, and click &#8216;Finish&#8217;. A new file should have been created and populated with the following code:
</p>
<pre name="code" class="java">
package classes
{
  import mx.controls.dataGridClasses.DataGridColumn;

  public class NestedDataGridColumn extends DataGridColumn
  {
    public function NestedDataGridColumn(columnName:String=null)
    {
      super(columnName);
    }

  }
}
</pre>
<h2>Step 10: Declaring the &#8216;nestedDataField&#8217; Property</h2>
<p>In the NestedDataGridColumn class, add a public bindable variable called &#8216;nestedDataField&#8217;. We&#8217;ll use this instead of the default &#8216;dataField&#8217; property to pass the field name. This is vital, because if the default &#8216;dataField&#8217; property is used, an error saying <strong>Error: Find criteria must contain at least one sort field value.</strong> will occur when we try to sort the DataGrid after having defined the custom sort function later on.
</p>
<h2>Step 11: Redefining the &#8216;itemToLabel&#8217; Funtion</h2>
<p>As you can see, the new class we created has already been populated with a constructor. Leave the constructor as it is and below that add the following function:
</p>
<pre name="code" class="java">
override public function itemToLabel(data:Object):String
    {
      var fields:Array;
      var label:String;

      var dataFieldSplit:String = nestedDataField;
      var currentData:Object = data;

      //check if the nestedDataField value contains a '.' (i.e. is accessing a nested value)
      if(nestedDataField.indexOf(".") != -1)
      {
        //get all the fields that need to be accessed
        fields = dataFieldSplit.split("."); 

        for each(var f:String in fields)
        //loop through the fields one by one and get the final value, going one field deep every iteration
          currentData = currentData[f]; 

        if(currentData is String)
        //return the final value
          return String(currentData);
      }

      //if there is no nesting involved
      else
      {
        if(dataFieldSplit != "")
            currentData = currentData[dataFieldSplit];
      }

      //if our method hasn't worked as expected, resort to calling the default function
      try
      {
        label = currentData.toString();
      }
      catch(e:Error)
      {
        label = super.itemToLabel(data);
      }

      //return the result
      return label;
    }
</pre>
<p>Redefining the &#8216;itemToLabel&#8217; function is the key to being able to access nested data in your DataGrid. The itemToLabel function controls what is shown in the DataGrid rows. So we use it here to ask Flex to show the nested data in the manner that we have specified.</p>
<p>
As you can see, the function definition starts with the &#8216;override&#8217; keyword, which means the default pre-defined function of the same name is being overridden in favour of the function you have defined. Each statement is explained in the comments. In brief, what the function does is check if nested data fields is being accessed (if a &#8216;.&#8217; is present). If it is, get each data field name, and iterate through the dataProvider, going deeper each step by accessing the child field.
</p>
<p>The &#8216;itemToLabel&#8217; function is called by Flex with an argument which contains the ArrayCollection that was specified as the dataProvider to the dataGrid. All attributes of the NestedDataGridColumn (when it is used in the mxml file) are directly accessible, and any public properties defined in this class can be assigned a value in the MXML. In our NestedDataGrid.mxml file, we replace the &#8216;mx:DataGridColumn&#8217; components with &#8216;classes:NestedDataGridColumn&#8217; component, and assign the specific elements that we want to show in the columns to the &#8216;nestedDataField&#8217; attribute (which was declared in the &#8216;NestedDataGridColumn.as&#8217; file). The DataGridColumn now should look like this:
</p>
<pre name="code" class="xml">
    &lt;mx:DataGrid x="10" y="10" width="{meetingsPanel.width-40}" height="45%" dataProvider="{dataForGrid}"&gt;
      &lt;mx:columns&gt;
        &lt;classes:NestedDataGridColumn headerText="Priority" nestedDataField="priority" width="60"/&gt;
        &lt;classes:NestedDataGridColumn headerText="Presenter Name" nestedDataField="presenter.name"  sortable="false"/&gt;
        &lt;classes:NestedDataGridColumn headerText="Presenter Phone" nestedDataField="presenter.phone" width="90"  sortable="false"/&gt;
        &lt;classes:NestedDataGridColumn headerText="Date" nestedDataField="date" width="110"/&gt;
        &lt;classes:NestedDataGridColumn headerText="Time" nestedDataField="time" width="70"/&gt;
        &lt;classes:NestedDataGridColumn headerText="Place" nestedDataField="place" width="70"/&gt;
      &lt;/mx:columns&gt;
    &lt;/mx:DataGrid&gt;
</pre>
<p>Note that I&#8217;m directly specifying the &#8216;nestedDataField&#8217; property as the &#8220;presenter.name&#8221; and &#8220;presenter.phone&#8221; here. Also, I&#8217;ve added widths to the columns and set the width of the &#8216;mx:Panel&#8217; component to 600px for better display. I&#8217;ve added the &#8217;sortable&#8217; property to be false to the two new columns. If you remove this (or set it to true) and run the program the column won&#8217;t sort. We&#8217;ll solve this in the next step by defining our own sort function. For now the application should look like this:
</p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/090_FlexNestedGrids/Preview/preview_non_sorted.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/milestone.jpg" alt="" style="border:none"></a>
</div>
<h2>Step 12: Writing the Custom Sort Function</h2>
<p>The only thing left now is to define the custom sorting function so that sorting will also be enabled in all the fields (say, you want to sort the presenter names alphabetically). Add the function called &#8216;mySortCompareFunction&#8217; below the &#8216;itemToLabel&#8217; function as given:</p>
<pre name="code" class="java">
    private function mySortCompareFunction(obj1:Object, obj2:Object):int{
      var fields:Array;
      var dataFieldSplit:String = nestedDataField;
      var currentData1:Object = obj1;
      var currentData2:Object = obj2;

      if(nestedDataField.indexOf(".") != -1)
      {
        fields = dataFieldSplit.split(".");

        for each(var f:String in fields){
          currentData1 = currentData1[f];
          currentData2 = currentData2[f];
        }

      }
      else
      {
        if(dataFieldSplit != ""){
            currentData1 = currentData1[dataFieldSplit];
            currentData2 = currentData2[dataFieldSplit];
         }
      }

      if(currentData1 is int &#038;&#038; currentData2 is int){
        var int1:int = int(currentData1);
        var int2:int = int(currentData2);
        var result:int = (int1>int2)?-1:1;
        return result;
      }
      if(currentData1 is String &#038;&#038; currentData2 is String){
        currentData1 = String(currentData1);
        currentData2 = String(currentData2);
        return (currentData1>currentData2)?-1:1;
      }
      if(currentData1 is Date &#038;&#038; currentData2 is Date){
        var date1:Date = currentData1 as Date;
        var date2:Date = currentData2 as Date;
        var date1Timestamp:Number = currentData1.getTime();
        var date2Timestamp:Number = currentData2.getTime();
        return (date1Timestamp>date2Timestamp)?-1:1;
      }

      return 0;
    }    
</pre>
<p>
This function will be called by Flex with two objects, and it&#8217;s expected to return either -1.0 or 1 depending on whether the first object is greater than, equal to, or less than, respectively, the second object. Flex takes care of the actual sorting.</p>
<p>
This function uses the same logic as the &#8216;itemToLabel&#8217; function to get the appropriate nested value. Then depending upon the type of the value (whether it be int, String, or Date) it compares it appropriately, and returns -1 if &#8216;currentData1&#8242; is greater than &#8216;currentData2&#8242;, 0 if they are equal, and 1 if &#8216;currentData2&#8242; is greater than &#8216;currentData1&#8242;.
</p>
<h2>Step 13: Hooking up the Custom Sort Function</h2>
<p>If you noticed, &#8216;customSortCompareFunction&#8217; is not a predefined function in the class DataGridColumn which we override. This function has to be assigned as the sorting function in a different way. We have to assign to the pre-defined variable &#8217;sortCompareFunction&#8217; the name of the sorting function, which is &#8216;customSortCompareFunction&#8217; in our case. This should be done inside the constructor. The constructor now looks like this:
</p>
<pre name="code" class="java">
public function NestedDataGridColumn(columnName:String=null)
    {
      //the custom sort function being assigned to the pre-defined variable
      sortCompareFunction = mySortCompareFunction;
      super(columnName);
    }
</pre>
<p>Once this is done, you&#8217;re all set. You now have a custom class that can handle arbitrarily nested data to show in a DataGrid. And you can sort the grid as you want.</p>
<h2>Conclusion</h2>
<p>Today you learnt how to circumvent a limitation of the FlexDataGrid class to get arbitrarily nested data, and show it in a DataGrid. You also learned how to define your own sorting function so that the grid remains sortable. You can now use this NestedDataGridColumn in all your applications without any overhead.</p>
<p>You can further extend the &#8216;itemToLabel&#8217; function to include other arbitrary format of access &#8211; say, accessing arrays inside the child objects, or accessing xml attributes. You can also further extend the sort function to sort other types of data. You might also be able to add other features like colouring the rows based on the meeting priority and showing more details about the presenter by clicking a row.</p>
<p>Thanks for reading <img src='http://active.tutsplus.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/working-with-the-flex-datagrid-and-nested-data-structures/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Working with the Debugger in Adobe Flex Builder</title>
		<link>http://active.tutsplus.com/tutorials/flex/working-with-adobe-flex-builders-debugger/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/working-with-adobe-flex-builders-debugger/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 12:00:36 +0000</pubDate>
		<dc:creator>Willy Ci</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Tools & Tips]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1600</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Many Flash developers use either the Alert class for debugging, or trace statements due to associations with Flash. Flex does have a true debugger and it&#8217;s a great tool. I&#8217;m going to demonstrate how to get to grips with it in this tutorial.</p>
<p><span id="more-1600"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/Flex_debug_tutorial.zip" target="_blank"><img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a>
</div>
<h2>Introduction</h2>
<p>Compiler errors are easy to spot and fix. You&#8217;re given a red dot with a X in it, telling you where and what the problem is.</p>
<p>Runtime errors are harder to trace. Debugger helps developers by tracing runtime errors, giving a window to see what&#8217;s going on while the application is running, what values are set to, what happens inside a loop, or why the if statement isn&#8217;t working. </p>
<p>OK, let&#8217;s get started &#8211; but before we begin, here are some tools you&#8217;ll need:</p>
<h4>The Debug Version of Flash Player</h4>
<p>
Download this <a href="http://www.adobe.com/support/flashplayer/downloads.html">here</a>. During this tutorial I&#8217;m using “the Macintosh Flash Player 10 Plugin content debugger (Intel-based Macs) (ZIP, 6.03 MB)”.  To test which version of flash player you&#8217;ve installed, take a look <a href="http://blog.Flexexamples.com/about-you/">at this handy tool</a> by Peter deHaan, who incidentally has a great blog <img src='http://active.tutsplus.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/check_flash_player_version.png" width="600" /><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/check_flash_player_version.png" target="_blank">View Full Size</a>
</div>
<h4>Adobe Flex Builder 3</h4>
<p>
Of course, you&#8217;ll need this. If you don&#8217;t have it you can always get a free copy:</p>
<ul>
<li>Free to all education customers: <a href="https://freeriatools.adobe.com/Flex/">https://freeriatools.adobe.com/Flex/</a></li>
<li>Free to unemployed developers: <a href="https://freeriatools.adobe.com/learnFlex/">https://freeriatools.adobe.com/learnFlex/</a></li>
</ul>
<h4>Other Useful Goodies</h4>
<p>Samples with code</p>
<ul>
<li><a href="http://examples.adobe.com/Flex3/componentexplorer/explorer.html">http://examples.adobe.com/Flex3/componentexplorer/explorer.html</a></li>
<li><a href="http://examples.adobe.com/Flex3/consulting/styleexplorer/Flex3StyleExplorer.html">http://examples.adobe.com/Flex3/consulting/styleexplorer/Flex3StyleExplorer.html</a></li>
</ul>
<p>Adobe® Flex™ 3.3 Language Reference</p>
<ul>
<li><a href="http://livedocs.adobe.com/Flex/3/langref/">http://livedocs.adobe.com/Flex/3/langref/</a></li>
<li><a href="http://livedocs.adobe.com/Flex/3/html/index.html">http://livedocs.adobe.com/Flex/3/html/index.html</a></li>
</ul>
<h2>Notes</h2>
<p>
The screen captures in this tut are made on Mac, but should be &plusmn; the same on PC. My window perspective maybe different from what you see, but you can find all the tabs under the window menu.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/list_windows.png" width="288" height="508" /></div>
<p>IF you&#8217;re ready, let’s get started!</p>
<h2>Step 1: Setup Break Points</h2>
<p>I&#8217;ve created a new Flex project; very simple, one panel with two buttons in it.  Each button will call its click function;  b1_click()  will run a loop, call update_Label() function. b2_click() will create a runtime error, since there is no such thing as n_error value.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/01-code-code.png" width="600"<br />
 /><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/01-code-code.png" target="_blank">View Full Size</a></div>
<p>
<b>What is a breakpoint?</b> A breakpoint is set on an executable line of a program. If the breakpoint is enabled when you debug, the execution suspends before that line of code executes.  In order to suspend the application while it is running, you need set a breakpoint. It&#8217;s easy to do; double-click on the empty space next to the line number. Double-click on it again to remove.</p>
<p>I set two breakpoints; lines 10 and 20 (two blue dots show up in the margin). If I click on button1, it will stop on line 10, click on button2 it will stop on line 20.</p>
<p>You can see all your breakpoints in the “Breakpoints” tab and they can be added or removed any time you wish. Additionally, you can use the check boxes to temporarily enable/disable them.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/03-list-breakpoints.png" /></div>
<p>
If you want to watch how the num is changed over time, highlight the value, right-click, Select “Watch ‘num’ ”.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/04-create expresion.png" /></div>
<p>
“num” is now added to the Expressions tab.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/05-expression-tab.png" alt="" width="600"<br />
 /><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/05-expression-tab.png" target="_blank">View Full Size</a></div>
<h2>Step 2: Start Debug Mode and Check Some Values</h2>
<p>Now we have everything setup, let’s start the debug section. Click on the icon which looks like a bug
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/06-run-debugger-1.png" width="600"<br />
 /><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/06-run-debugger-1.png" target="_blank">View Full Size</a></div>
<p>or select it from the menu:
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/07-run-debugger-2.png" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/07-run-debugger-2.png" target="_blank">View Full Size</a></div>
<h2>Step 3: App Started</h2>
<p>As the app starts running, you can see it in the browser but nothing happens, what to do next? The break point is set inside the function, so we need exectue the function.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/08-nothing happen after start.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/08-nothing happen after start.png" target="_blank">View Full Size</a></div>
<h2>Step 4: Trigger the Breakpoint</h2>
<p>To trigger the breakpoint, click on “Button 1” to call the b1_click() function. The app then stops at line 10 and num is still 0 since the code &#8220;num += 1;&#8221; hasn&#8217;t executed yet. Look at the Debug tab; some icons light up and some values are now visible.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/09-click on but-1-num is 0.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/09-click on but-1-num is 0.png" target="_blank">View Full Size</a></div>
<h2>Step 5: Variables Tab</h2>
<p>First let&#8217;s take a look the Variables tab;  a few things to note:</p>
<ul>
<li><b>This</b>: includes all the values in the application</li>
<li><b>Event</b>: current event passed in</li>
<li><b>i</b>: value defined in this function</li>
</ul>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/10-list of variabes.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/10-list of variabes.png" target="_blank">View Full Size</a></div>
<p>Open up “this”, a long list will show up. The list will keep getting longer and longer then you&#8217;ll notice your computer slowing down <img src='http://active.tutsplus.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/11-find-b2-label.png" alt="" /></div>
<h2>Step 6: Create Watch Expression</h2>
<p>Since I know I want to focus on “button2.label”, let’s find it and right-click to select “Create Watch Expression”.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/12-add-b2.label-to expresion.png" alt="" /></div>
<h2>Step 7:  Expression Tab</h2>
<p>Now take a look the Expressions tab, simple and clean, just the way I like it. Two variables we are looking at now, “num” we created earlier, and “this.button2.label”.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/13-b2-label in expresions.png" alt="" /></div>
<h2>Step 8: Using the Step Controls</h2>
<p>Now let&#8217;s take a look at the debug tab. In this tab, you&#8217;ll see that some icons are now enabled, a list of function names, and component names. The screenshot below shows that  we&#8217;re currently in the  myLoop function and that the component “button2” performed an action “click” to call this function.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/14-debug-tab-close look.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/14-debug-tab-close look.png" target="_blank">View Full Size</a></div>
<h2>Step 9: Learning the Step Controller</h2>
<p>Those icons we noticed (you can find them under menu &gt; run too), what are they for?
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/15-steps-buttons.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/15-steps-buttons.png" target="_blank">View Full Size</a></div>
<p>When a thread is suspended, the step controls can be used to step through the execution of the program line-by-line.</p>
<p>Often, you can also use shortcuts &#8211; memorize them!</p>
<ul>
<li>Resume – F8 key (not for Mac user) continue run application.</li>
<li>Terminate – stop debug mode, application will keep running, but you can’t trace anymore.</li>
<li>Step Over – F6 key, go to next line of code.</li>
<li>Step Into – F5 key, if current line of code is calling other function, look into that function.</li>
<li>Step Return – F7 key, get out of that function.</li>
</ul>
<p>F6 and F8 will be your best friends, remember them!</p>
<h2>Step 10: Using the F6 Key</h2>
<p>Let’s press F6 a few times. Keep your eye on the Expression tab, see what the value is changing to.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/16-click on resume-once-or-F8.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/16-click on resume-once-or-F8.png" target="_blank">View Full Size</a></div>
<h2>Step 11: Value Changing</h2>
<p>Keep pressing F6! The value of num is changing in the Expressions tab.</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/17-press-F6-goto-begin.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/17-press-F6-goto-begin.png" target="_blank">View Full Size</a></div>
<h2>Step 12: Using the F5 Key</h2>
<p>If your loop never ends, ends early, or never even begins, you can look into the action closely to see what&#8217;s happening. Once we&#8217;ve finished the loop, the second function  update_Label() is called. Pressing F6 will step over it, but we want to see what happens <em>within</em> the update_Label(). Press F5 &#8220;step into&#8221;.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/18-before-go-into-child-function-F5.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/18-before-go-into-child-function-F5.png" target="_blank">View Full Size</a></div>
<p>Now we&#8217;re in the update_Label() function.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/19-step-into-child-function.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/19-step-into-child-function.png" target="_blank">View Full Size</a></div>
<h2>Step 13: Using the F7 Key</h2>
<p>You can press F7 to go back to myLoop(). The value of the “this.button2.label” has been changed.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/20-step-return to parent-function.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/20-step-return to parent-function.png" target="_blank">View Full Size</a></div>
<h2>Step 14 Using the F8 Key</h2>
<p>Let’s press F8 to resume the app. Now the button2’s label has been updated.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/19-1-click on resume-label updated.png" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/19-1-click on resume-label updated.png" target="_blank">View Full Size</a></div>
<h2>Step 15: Read the Error Messages in Debug Session</h2>
<p>OK, now let&#8217;s test the bug in the app. We know there&#8217;s a bug in the b2_click() function, so let’s see it in action. Click on “Button 2”, this will call the b2_click() function, and the app will stop at the error.</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/25-click on b2-stop at error.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/25-click on b2-stop at error.png" target="_blank">View Full Size</a></div>
<h2>Step 16: Debug Tab</h2>
<p>Take a close look at the Debug tab. In here it tells you what the error is, and who is calling.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/26-close look at debug-tab.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/26-close look at debug-tab.png" target="_blank">View Full Size</a></div>
<h2>Step 17: Console Tab</h2>
<p>Here&#8217;s what is displayed in the Console tab. It gives you more information about the error and line number where the error occurred.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/27-close clook at console tab .png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/27-close clook at console tab .png" target="_blank">View Full Size</a></div>
<h2>Step 18: Change Values of Variables</h2>
<p>You can always change the value of variables while the application is suspended. For example, if I want to change button2.label from “num = 10” to “new label” I do the following: first find the variable &#8220;label&#8221;, right-click , select Change Value.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/20-find-b2-label-change-value.png" alt="" /></div>
<h2>Step 19: Set Value Popup Window</h2>
<p>The Set Value window pops up and displays the current value. </p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/21-set-value-window.png" alt="" /></div>
<h2>Step 20: Enter New Value</h2>
<p>I&#8217;m going to change that string to “new label”, then press OK.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/22-new-value-click on.png" alt="" /></div>
<h2>Step 21: Update New Value</h2>
<p>Now in the Variables tab, the new value is set.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/23-update in variables tab.png" alt="" /></div>
<h2>Step 22: Resume App</h2>
<p>Resume the application, you&#8217;ll see the label has been updated.
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/24-new-value-updated-display.png" alt="" width="600"<br />
/><a class="clearfix" href="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/24-new-value-updated-display.png" target="_blank">View Full Size</a></div>
<h2>Conclusion</h2>
<p>Alright, now you know how to use the debugger! Here&#8217;s a quick summary:</p>
<ul>
<li>Double-click Create a breakpoint.</li>
<li>Click on the bug icon to start debug mode.</li>
<li>Trigger the action to  suspend the application.</li>
<li>Variables tab tells you what the value is.</li>
<li>Console tab tells you what and where the error is (if any).</li>
<li>Debug tab tells you who called who and who did wha.t</li>
<li>Then waits for you to tell it what action to take.</li>
</ul>
<p>If you think you&#8217;re ready to test your debug skills now, go try them on your own application!
</p>
<p>One last tip for those new to Flex: remember to always export a release build, not the debug build which is much bigger. I hope you enjoyed reading along!
</p>
<div class="tutorial_image"><img border="0" src="http://flashtuts.s3.cdn.plus.org/077_FlexDebugger/30-release build.png" alt="" /></div>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/working-with-adobe-flex-builders-debugger/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Creating a Feed Reader Widget with Adobe Flex 3</title>
		<link>http://active.tutsplus.com/tutorials/flex/creating-a-feed-reader-widget-with-adobe-flex-3/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/creating-a-feed-reader-widget-with-adobe-flex-3/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 12:00:22 +0000</pubDate>
		<dc:creator>Mario Santos</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1202</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>In this tutorial you&#8217;ll learn how to create your own Flex feed reader application. In this case, the final result will be a simple feed reader which can be used in your blog or site to display your favorite feeds.</p>
<p><span id="more-1202"></span> </p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/source.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Pre-Requirements</h2>
<p>To complete this tutorial you&#8217;ll need some things:</p>
<ul>
<li>A copy of Flex Builder 3.x, you can download a trial for free <a href="http://www.adobe.com/products/flex/" title="adobe.com">from the Adobe site</a>.</li>
<li>The opensource library <b>as3syndicationlib</b> (I won&#8217;t re-invent the wheel by creating one syndication lib!) which can be downloaded <a href="http://code.google.com/p/as3syndicationlib/downloads/list/" title="as3syndicationlib at google code!">here</a>.</li>
<li>Images I&#8217;ve used in the project. You can download them <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/images.zip" title="Project Images">here</a>.</li>
<li>The <a href="XMLUtil.zip" title="XMLUtil class">XMLUtil.as</a> class to validate XML Structure, available from <a href="http://code.google.com/p/as3corelib/" title="coreLib google page">corelib Package</a>.</li>
<li>Some free time!</li>
</ul>
<h2>Step 1: Create a New Project</h2>
<p>Well, this is probably something that you already know how to do, but just to remind you and ensure we&#8217;re working on the same page:</p>
<p>Begin by running Flex Builder then create a new project (Menu File &gt; New &gt; Flex Project). Make sure you enter the same properties in the dialog as shown here:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/1.jpg" alt="Creating a new Project" width="600" height="328" /></div>
<p>Just enter as the Project name: <b>WFlexibleFeed</b>. All the rest remains like it is! Press the &#8220;finish&#8221; button! Your project is created!</p>
<h2>Step 2: Setting up Required Libs</h2>
<p>Open the downloaded xmlsyndication-.85.zip lib from the provided <a href="http://code.google.com/p/as3syndicationlib/downloads/list/" title="as3syndicationlib at google code!">download source</a>, browse the archive xmlsyndicationlib/bin/ and extract the xmlsyndication.swc into the libs folder of your flex project. It should result in the following structure:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/2.JPG" alt="Project Libs Path" width="219" height="146" /></div>
<p>This library file will be automatically loaded because it&#8217;s in the libs folder. You don&#8217;t need to do anything else to load this library, you just need to import its classes before use. (Note, if you do not have the bin-release folder don&#8217;t get worried, this is not important for now!).</p>
<h2>Step 3: Defining Project Details</h2>
<p>In this step, you&#8217;ll setup some folders that we&#8217;ll use along with our project. The first one is a folder &quot;assets&quot; in the project root (src folder). To create it just right-click on the src folder, then go to (New &gt; Folder) and name it &quot;assets&quot;.</p>
<p>Repeat the same actions for a &quot;com&quot; folder.</p>
<p>When this is done, extract the images provided in the <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/images.zip" title="Project Images">images.zip</a> file to the assets folder (you can select them and drag them to the assets folder in flex builder). You should now have the following structure in the flex navigator project:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/3.JPG" alt="Project Libs Path" width="241" height="239" /></div>
<h2>Step 4: Creating a Simple Layout</h2>
<p>This &quot;Simple layout&quot; can be whatever you want, it just needs to contain a datagrid, a textinput with feed address, a button to load and another to refresh. To get my layout:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/4.JPG" alt="Project Libs Path" width="598" height="320" /></div>
<p>you&#8217;ll need to insert the following code into WFlexibleFeed.mxml within the &lt;mx:Application&gt; tags:</p>
<pre name="code" class="javascript">&lt;mx:Canvas width=&quot;336&quot; height=&quot;208&quot; horizontalCenter=&quot;0&quot; verticalCenter=&quot;0&quot; borderColor=&quot;#A70101&quot; backgroundColor=&quot;#242424&quot;&gt;
		&lt;mx:Canvas x=&quot;0&quot; y=&quot;0&quot; width=&quot;336&quot; height=&quot;24&quot; backgroundColor=&quot;#333333&quot;&gt;
			&lt;mx:Label x=&quot;9&quot; y=&quot;4&quot; text=&quot;WFlexible Feed v1.0&quot; width=&quot;298&quot; color=&quot;#BBBBBB&quot;/&gt;
		&lt;/mx:Canvas&gt;
		&lt;mx:Label x=&quot;11&quot; y=&quot;27&quot; text=&quot;Feed:&quot; color=&quot;#FFFFFF&quot;/&gt;
		&lt;mx:Image x=&quot;310&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Rss.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Switch Feed!&quot; click=&quot;switchFeed()&quot;/&gt;
		&lt;mx:Image x=&quot;291&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Refresh.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Refresh&quot; click=&quot;refresh()&quot;/&gt;
		&lt;mx:Image x=&quot;50&quot; y=&quot;103&quot; source=&quot;@Embed(source='assets/logo.png')&quot;/&gt;
		&lt;mx:DataGrid x=&quot;10&quot; y=&quot;47&quot; height=&quot;155&quot; width=&quot;316&quot; id=&quot;dataGridItems&quot; dataProvider=&quot;{DP}&quot; useHandCursor=&quot;true&quot;  backgroundAlpha=&quot;0.4&quot;&gt;
			&lt;mx:columns&gt;
				&lt;mx:DataGridColumn headerText=&quot;Feed entries...&quot; dataField=&quot;title&quot; sortable=&quot;false&quot;/&gt;
			&lt;/mx:columns&gt;
		&lt;/mx:DataGrid&gt;
		&lt;mx:TextInput x=&quot;56&quot; y=&quot;26&quot; width=&quot;227&quot; text=&quot;http://feedproxy.google.com/flashtuts/&quot; height=&quot;20&quot; toolTip=&quot;Click to Edit Feed URL&quot; id=&quot;feedURI&quot; styleName=&quot;myTextInput&quot;/&gt;

	&lt;/mx:Canvas&gt;</pre>
<p>As you can see, I&#8217;ve already made some modifications into some components arguments, like giving a <b>DP</b> variable to dataGrid dataProvider, putting the feed addresse&#8230; well.. you can see for yourself. These are the main project components, we&#8217;ll use a little of CSS code (yes, Flex supports css) to make it more beautiful.</p>
<h2>Step 5: Creating a Stylesheet</h2>
<p>This process is very simple. Copy my css code here to make it similar. If you want some other colors, just try the <a href="http://examples.adobe.com/flex3/consulting/styleexplorer/Flex3StyleExplorer.html" title="Flex 3 Style Explorer">Flex 3 style explorer</a> and create your own css styles.</p>
<p>Copy this css into your application, right after the &lt;mx:Application&gt; tag:</p>
<pre name="code" class="css">&lt;mx:Style&gt;
.myTextInput {
   borderStyle: none;
   borderColor: #505050;
   backgroundAlpha: 0;
   backgroundColor: #ffffff;
   color: #5C5C5C;
   themeColor: #FFFFFF;
}
Button {
   cornerRadius: 0;
   borderColor: #000000;
   themeColor: #333333;
}
Alert {
backgroundColor: #000000;
borderColor: #000000;
backgroundAlpha: 0.9;
borderAlpha: 0.9;
color: #FFFFFF;
}
ToolTip {
   backgroundColor: #333333;
   color: #cccccc;
}
	DataGrid {
   backgroundAlpha: 1;
   backgroundColor: #666666;
   alternatingItemColors: #666666, #333333;
   headerColors: #000000, #000000;
   horizontalGridLines: true;
   horizontalGridLineColor: #000000;
   verticalGridLines: false;
   verticalGridLineColor: #cccccc;
   rollOverColor: #ffffff;
   textRollOverColor: #000000;
   borderColor: #000000;
   selectionColor: #ffffff;
   color: #ffffff;
   headerStyleName: &quot;mydataGridHeaderStyle&quot;;
}
.mydataGridHeaderStyle {
  color: #ffffff;
  fontWeight: normal;
  fontStyle: italic;
  textDecoration: none;
  letterSpacing: 1;
  }

VScrollBar {
  cornerRadius: 0;
  highlightAlphas: 0.46, 0.27;
  fillAlphas: 1, 1, 1, 1;
  fillColors: #666666, #333333, #cccccc, #999999;
  trackColors: #666666, #333333;
  themeColor: #000000;
  borderColor: #000000;
  iconColor: #111111;
  thumbOffset: 1;
}
&lt;/mx:Style&gt;</pre>
<p>This will produce a better widget look and feel, right?</p>
<h2>Step 6: Create the Feed Handler</h2>
<p>Yes, even with the xmlsyndication lib you&#8217;ll need to code a class to handle the parser output, or you&#8217;ll get nothing to work. So, you&#8217;ll need to create a new Action Script Class, just go to menu File &gt; New &gt; Action Script Class and enter the settings as seen in the image below. We&#8217;ll also need a class (from corelib) to validate the XML format. Just download the class <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/XMLUtil.zip" title="XMLUtil from corelib project">here</a> and put it in your &quot;com&quot; folder.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/5.JPG" alt="Project Libs Path" width="501" height="436" /></div>
<p>This will create a new folder &quot;feed&quot; in the &quot;com&quot; folder and a &quot;FeedParser.as&quot; file too. The Action Script editor will now open.</p>
<h2>Step 7: Code the Parser Class</h2>
<p>Just copy this code into the FeedParser.as Class:</p>
<pre name="code" class="javascript">package com.feed
  {
  //necessary imports
  import com.XMLUtil; //usefull for correct xml format XMLUtil.as from corelibPackage
  import com.adobe.xml.syndication.atom.Atom10; //imports from xmlsyndicationlib from adobe
  import com.adobe.xml.syndication.atom.Entry;
  import com.adobe.xml.syndication.rss.Item20;
  import com.adobe.xml.syndication.rss.RSS20;

  //some flash imports needed to work with the feed
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.IOErrorEvent;
  import flash.events.SecurityErrorEvent;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import flash.net.URLRequestMethod;

  //two classes used in the process
  import mx.collections.ArrayCollection;
  import mx.controls.Alert;

  public class FeedParser extends Sprite
  {
  private var feedURI:String=&quot;http://feedproxy.google.com/flashtuts/&quot;; //default feed
  private var feedLoader:URLLoader; //the feed loader
  public var FEED_DATA:ArrayCollection=null; //the feed data

  public function FeedParser(url:String)
  {
  feedURI=url; //on initiate, set the feed url
  }

  public function loadFeed():void {
   //add the listener events and load the feed
   feedLoader = new URLLoader();
   var req:URLRequest = new URLRequest(feedURI);
   req.method = URLRequestMethod.GET;
   feedLoader.addEventListener(Event.COMPLETE, completeHandler);
   feedLoader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
   feedLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
   feedLoader.load(req);
  }

  //error handling function
 private function errorHandler(e:Event):void {
  if(e.type==SecurityErrorEvent.SECURITY_ERROR) Alert.show(&quot;Security Error while reading feed URI!&quot;);
  else if(e.type==IOErrorEvent.IO_ERROR) Alert.show(&quot;I/O Error while reading feed URI!&quot;);
  else Alert.show(e.type+&quot; Error while reading feed URI!&quot;);
  }

  //on result function
  private function completeHandler(evt:Event):void {
  var feedData:String=feedLoader.data; //get the feed contents
  var feed_type:String=&quot;RSS&quot;;
  var entrys:Array;
  var tempObj:Object;

  //old way to detect feed type &amp; version
  if(feedData.search(&quot;rss version=\&quot;2.0\&quot;&quot;)&gt;-1) trace(&quot;FEED RSS 2.0&quot;);
  else if(feedData.search(&quot;rss version=&quot;)&gt;-1) trace(&quot;FEED RSS &lt;=1.0&quot;);
  else if(feedData.search(&quot;Atom&quot;)&gt;-1) trace(&quot;FEED ATOM&quot;);

  if(feedData.search(&quot;xmlns=\&quot;http://www.w3.org/2005/Atom&quot;)&gt;-1) feed_type=&quot;ATOM&quot;; //check if is an ATOM feed

 //if is a RSS feed
  if(feed_type==&quot;RSS&quot;) {
   var rss:RSS20= new RSS20();
   try { rss.parse(feedData); }  //parse it
   catch(e:Error) {
    Alert.show(&quot;Error Parsing Feed!\nInvalid link?&quot;);
    return void;
  } 

  entrys=rss.items; //get the items
  FEED_DATA = new ArrayCollection(); //initiate the arrayCollection

  //validate the feed
  if(!XMLUtil.isValidXML(feedData)) {
   Alert.show(&quot;Invalid or bad feed URI or structure!&quot;);
   return void;
  } 

  //built an array Collection with the results
  for each(var entry:Item20 in entrys)
  {
   tempObj = new Object();
   tempObj.title=entry.title;
   tempObj.link=entry.link;
   tempObj.desc=entry.description;
   tempObj.author=entry.creator;
   FEED_DATA.addItem(tempObj);
   }
  }
else if(feed_type==&quot;ATOM&quot;) { //else if is a ATOM feed, do the same process
  var rssA:Atom10 = new Atom10()
  try { rssA.parse(feedData); }
  catch(e:Error) {
   Alert.show(&quot;Error Parsing Feed!\nInvalid link?&quot;);
   return void;
  } 

  var entrysA:Array = rssA.entries;
  var tempObj2:Object;
  FEED_DATA = new ArrayCollection();

  if(!XMLUtil.isValidXML(feedData)) {
   Alert.show(&quot;Invalid / bad feed URI or structure!&quot;);
   return void;
  } 

  for each(var entryA:Entry in entrysA)
  {
   tempObj2 = new Object();
   tempObj2.title=entryA.title;
   tempObj2.link=entryA.links[0].href;
   tempObj2.desc=entryA.content;
   tempObj2.author=entryA.authors;
   FEED_DATA.addItem(tempObj2);
   }
  }
  else { //impossible to find feed type...
    Alert.show(&quot;Cannot detect feed type\nInvalid link?&quot;)
   return void;
  }

  this.dispatchEvent(new Event(&quot;DataReady&quot;)); //data is now ready to be used! listen this event to acess data!
  }
 }
}
</pre>
<p>Save your file now!</p>
<h2>Step 8: Understanding the Feed Parser</h2>
<p>Easy, just read the comments in the code and you&#8217;ll be able to understand it. If you don&#8217;t want to, you just need to know what we&#8217;ll write to use it: </p>
<pre name="code" class="javascript">
import com.feed.FeedParser;		

private var parser:FeedParser;

parser = new FeedParser(&quot;http://feed.url/feed/&quot;);
parser.addEventListener(&quot;DataReady&quot;, dataHandler);
parser.addEventListener(&quot;DataError&quot;, dataErrorHandler);
parser.loadFeed();
</pre>
<p>Well, this is a simplified version of how to work with our class. We&#8217;ll see it in use&#8230; keep following the tutorial..</p>
<h2>Step 9: Take a Break</h2>
<p>This is a relaxing step, maybe that was too much code at once, let me explain the workflow:</p>
<p>We have a syndicationlib responsible for reading the feed and putting the contents into an objects class. Our FeedParser class&#8217; main purpose is to prepare, call and handle the output from the syndication class.</p>
<p>Then there&#8217;s our main application, which will call the FeedParser class and wait for the DataReady event to load the feed items into the datagrid dataprovider.</p>
<h2>Step 10: Code First Load Function</h2>
<p>This is the function that will make our feed reader work. We&#8217;ll code an init() function which will be called on the creationComplete event of our application.</p>
<p>Write necessary imports:</p>
<pre name="code" class="javascript">
import mx.collections.ArrayCollection;
import mx.controls.Alert;

import com.feed.FeedParser;

private var parser:FeedParser;
private var currentFeed:String;

[Bindable]
private var DP:ArrayCollection;
</pre>
<p>Our initial function:</p>
<pre name="code" class="javascript">
private function init():void {
	DP=null;
	Security.allowDomain(feedURI.text); //useful some times, try to avoid domain access errors
	Security.allowInsecureDomain(feedURI.text); //useful some times, try to avoid domain access errors
	//in some cases you'll need (if possible) to load an external crossdomain.xml file... 

	parser = new FeedParser(feedURI.text);
	parser.addEventListener(&quot;DataReady&quot;, dataHandler);
	parser.addEventListener(&quot;DataError&quot;, dataErrorHandler);
	parser.loadFeed();
}
</pre>
<h2>Step 11: Code the Event Handlers</h2>
<p>Lets code the 3 necessary event handlers.</p>
<p>The error handler:</p>
<pre name="code" class="javascript">
private function dataErrorHandler(evt:Event):void {
	Alert.show(&quot;Some Error ocurred reading data from feed!\n\nPossible Causes:\nInvalid feed URL\nInvalid feed type (Not RSS 2.0)\nInvalid feed format&quot;);
}
</pre>
<p>The success handler:</p>
<pre name="code" class="javascript">
private function dataHandler(evt:Event):void {
	DP = new ArrayCollection();
	DP=parser.FEED_DATA;
	currentFeed=feedURI.text; //we save the feedURL to a variable, needed to refresh the feed and avoid recalls
}
</pre>
<p>Now we have our feed items in the DP arrayCollection, ready to use into the dataGrid. I also want to have a self-refresh mechanism (so the feed entries updates are outputted to datagrid), we&#8217;ll create it now.</p>
<h2>Step 12: Coding a Self-Update Mechanism</h2>
<p>The process is very easy, we&#8217;ll need a timer to execute a new call to get feed contents, so&#8230;</p>
<p>Declare the timer next to our var parser:</p>
<pre name="code" class="javascript">
private var updateTimer:Timer = new Timer(600000);
 //means 600 seconds = 10 minutes</pre>
<p>Write loadAutoUpdate(); on the dataHandler function on bottom:</p>
<pre name="code" class="javascript">
private function dataHandler(evt:Event):void {
	DP = new ArrayCollection();
	DP=parser.FEED_DATA;
	currentFeed=feedURI.text; //we save the feedURL to a variable, needed to refresh the feed and avoid recalls
	loadAutoUpdate(); //load the update engine
}
</pre>
<p>and let&#8217;s code the update function:</p>
<pre name="code" class="javascript">
private function loadAutoUpdate():void {
	try {
		updateTimer.stop(); //we try to stop a possible started timer
		updateTimer.removeEventListener(TimerEvent.TIMER, onTime); //remove the eventListener
	}
	catch(e:Error) { trace(&quot;Error on timer!&quot;) } //handle possible errors

	updateTimer.addEventListener(TimerEvent.TIMER, onTime); //add listener again
	updateTimer.start(); //start the timer
}
</pre>
<p>Finally, we need the onTime function to handle time events every 10 minutes:</p>
<pre name="code" class="javascript">
private function onTime(evt:TimerEvent):void {
	feedURI.text=currentFeed;
	init();
}
</pre>
<p>As people can change the feedURI field, we save it into a currentFeed variable until a new feed data is parsed.</p>
<h2>Step 13: Understanding the Self-Update Mechanism</h2>
<p>The workflow is simple. When the init() function is called, the feedParser is loaded.</p>
<p>In this function we reset the DP (data provider), setup the security policies (to avoid some domain access errors) and load the feed:</p>
<pre name="code" class="javascript">
(...)
parser.loadFeed();
(...)
</pre>
<p>Finally, the feed is parsed and the DP is populated with feed items:</p>
<pre name="code" class="javascript">
(...)
DP = new ArrayCollection();
DP=parser.FEED_DATA;
(...)
</pre>
<p>and we load the update mechanism that will be loaded every 10 minutes (~600 seconds / 600 000 miliseconds):</p>
<pre name="code" class="javascript">
(...)
private var updateTimer:Timer = new Timer(600000);
(...)
updateTimer.start();
(...)
</pre>
<p>That will call the onTime function every 10 minutes and recall the init function to reload the feed.</p>
<pre name="code" class="javascript">
private function onTime(evt:TimerEvent):void {
	feedURI.text=currentFeed;
	init();
}
</pre>
<p>The main system is coded, now we just need to add some more actions.</p>
<h2>Step 14: Code Button Actions</h2>
<p>In this step we&#8217;ll need to code the functions to change to a new feed and refresh the current one.</p>
<p>The refresh function in quite simple: </p>
<pre name="code" class="javascript">
private function refresh():void {
	feedURI.text=currentFeed; //to avoid changes on textInput
	init(); //reload the feed
}
</pre>
<p>and the change feed function:</p>
<pre name="code" class="javascript">
private function switchFeed():void {
	if(currentFeed==feedURI.text) Alert.show("Please edit the feed url and try again!"); //we'll not switch feed to the same one!
	else init(); //load the feed because feedURI.text is not equal to actual feed URI.
}
</pre>
<h2>Step 15: Load the Things Up and Test Them</h2>
<p>We need to load the whole process on the creationComplete event of the application, just add to your mx:application tag:</p>
<pre name="code" class="javascript">
(...) creationComplete="init()" (...)
</pre>
<p>Try to run the application now! It&#8217;s working, right? We&#8217;ll now improve the application interaction..</p>
<h2>Step 16: Understanding the DP Elements</h2>
<p>The data provider <b>DP</b> is a copy from the FeedParser.FEED_DATA array collection, so we need to add the FEED_DATA structure into the FeedParser.as class:</p>
<pre name="code" class="javascript">
	tempObj = new Object();
   tempObj.title=entry.title;
   tempObj.link=entry.link;
   tempObj.desc=entry.description;
   tempObj.author=entry.creator;
   FEED_DATA.addItem(tempObj);
</pre>
<p>In here we can see each item contains one title, link, desc(ription) and author(s) elements. This will be useful if you want to display that information on the datagrid, though for the moment we only want to display the title (using dataField):</p>
<pre name="code" class="javascript">
&lt;mx:DataGridColumn headerText=&quot;Feed entries...&quot; dataField=&quot;title&quot; sortable=&quot;false&quot;/&gt;
</pre>
<p>If we need to display the <b>desc</b> or<b> link</b>, we just need to provide the field <b>desc</b> as dataField parameter in a new column.</p>
<h2>Step 17: Load the Item Webpage</h2>
<p>Of course, this is very useful! We just need to enable the double-click into the dataGrid by writing the following into the mx:Table tag:</p>
<pre name="code" class="javascript">doubleClickEnabled=&quot;true&quot; doubleClick=&quot;loadURL()&quot;</pre>
<p>and the loadURL() function: </p>
<pre name="code" class="javascript">
private function loadURL():void {
	if(dataGridItems.selectedIndex>-1) navigateToURL(new URLRequest(dataGridItems.selectedItem.link), "_blank"); //if there is any selected index, load the URL into another window.
}
</pre>
<p>Quite easy, so we&#8217;ve almost finished the feedReader, time to review the code.</p>
<h2>Step 18: Review the Code</h2>
<p>Time to compare your code with mine</p>
<p><strong>WFlexibleFeed.xmml</strong></p>
<pre name="code" class="javascript">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  &lt;mx:Application xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot; layout=&quot;absolute&quot; backgroundGradientAlphas=&quot;[1.0, 1.0]&quot; backgroundGradientColors=&quot;[#EBEBEB, #CBCBCB]&quot; creationComplete=&quot;init()&quot;&gt;
  &lt;mx:Style&gt;
  .myTextInput {
  borderStyle: none;
  borderColor: #505050;
  backgroundAlpha: 0;
  backgroundColor: #ffffff;
  color: #5C5C5C;
  themeColor: #FFFFFF;
  }
  Button {
  cornerRadius: 0;
  borderColor: #000000;
  themeColor: #333333;
  }
  Alert {
  backgroundColor: #000000;
  borderColor: #000000;
  backgroundAlpha: 0.9;
  borderAlpha: 0.9;
  color: #FFFFFF;
  }

  ToolTip {
  backgroundColor: #333333;
  color: #cccccc;
  }

  DataGrid {
  backgroundAlpha: 1;
  backgroundColor: #666666;
  alternatingItemColors: #666666, #333333;
  headerColors: #000000, #000000;
  horizontalGridLines: true;
  horizontalGridLineColor: #000000;
  verticalGridLines: false;
  verticalGridLineColor: #cccccc;
  rollOverColor: #ffffff;
  textRollOverColor: #000000;
  borderColor: #000000;
  selectionColor: #ffffff;
  color: #ffffff;
  headerStyleName: &quot;mydataGridHeaderStyle&quot;;
  }

.mydataGridHeaderStyle {
  color: #ffffff;
  fontWeight: normal;
  fontStyle: italic;
  textDecoration: none;
  letterSpacing: 1;
}

VScrollBar {
  cornerRadius: 0;
  highlightAlphas: 0.46, 0.27;
  fillAlphas: 1, 1, 1, 1;
  fillColors: #666666, #333333, #cccccc, #999999;
  trackColors: #666666, #333333;
  themeColor: #000000;
  borderColor: #000000;
  iconColor: #111111;
  thumbOffset: 1;
}

&lt;/mx:Style&gt;

&lt;mx:Script&gt;
  &lt;![CDATA[
  import mx.collections.ArrayCollection;
  import mx.controls.Alert;

  import com.feed.FeedParser;

  private var parser:FeedParser;
  private var updateTimer:Timer = new Timer(600000);

  [Bindable]
  private var DP:ArrayCollection;

  private var currentFeed:String;

  private function init():void {
   DP=null;
   Security.allowDomain(feedURI.text);
   Security.allowInsecureDomain(feedURI.text);
   parser = new FeedParser(feedURI.text);
   parser.addEventListener(&quot;DataReady&quot;, dataHandler);
   parser.addEventListener(&quot;DataError&quot;, dataErrorHandler);
   parser.loadFeed();
  }

  private function dataErrorHandler(evt:Event):void {
   Alert.show(&quot;Some Error ocurred reading data from feed!\n\nPossible Causes:\nInvalid feed URL\nInvalid feed type (Not RSS 2.0)\nInvalid feed format&quot;);
  }

  private function loadAutoUpdate():void {
   try {
    updateTimer.stop();
    updateTimer.removeEventListener(TimerEvent.TIMER, onTime);
   }
   catch(e:Error) { }

    updateTimer.addEventListener(TimerEvent.TIMER, onTime);
    updateTimer.start();
  }

  private function onTime(evt:TimerEvent):void {
    feedURI.text=currentFeed;
    init();
  }

  private function dataHandler(evt:Event):void {
    DP = new ArrayCollection();
    DP=parser.FEED_DATA;
    currentFeed=feedURI.text;
    loadAutoUpdate();
  }

  private function loadURL():void {
   if(dataGridItems.selectedIndex&gt;-1) navigateToURL(new URLRequest(dataGridItems.selectedItem.link), &quot;_blank&quot;);
  }

  private function refresh():void {
    feedURI.text=currentFeed;
    init();
  }

  private function switchFeed():void {
    if(currentFeed==feedURI.text) Alert.show(&quot;Please edit the feed url and try again!&quot;);
    else init();
  }

  ]]&gt;
  &lt;/mx:Script&gt;

  &lt;mx:Canvas width=&quot;336&quot; height=&quot;208&quot; horizontalCenter=&quot;0&quot; verticalCenter=&quot;0&quot; borderColor=&quot;#A70101&quot; backgroundColor=&quot;#242424&quot;&gt;
    &lt;mx:Canvas x=&quot;0&quot; y=&quot;0&quot; width=&quot;336&quot; height=&quot;24&quot; backgroundColor=&quot;#333333&quot;&gt;
     &lt;mx:Label x=&quot;9&quot; y=&quot;4&quot; text=&quot;WFlexible Feed v1.0&quot; width=&quot;298&quot; color=&quot;#BBBBBB&quot;/&gt;
    &lt;/mx:Canvas&gt;
   &lt;mx:Label x=&quot;11&quot; y=&quot;27&quot; text=&quot;Feed:&quot; color=&quot;#FFFFFF&quot;/&gt;
   &lt;mx:Image x=&quot;310&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Rss.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Switch Feed!&quot; click=&quot;switchFeed()&quot;/&gt;
   &lt;mx:Image x=&quot;291&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Refresh.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Refresh&quot; click=&quot;refresh()&quot;/&gt;
   &lt;mx:Image x=&quot;50&quot; y=&quot;103&quot; source=&quot;@Embed(source='assets/logo.png')&quot;/&gt;
   &lt;mx:DataGrid x=&quot;10&quot; y=&quot;47&quot; height=&quot;155&quot; width=&quot;316&quot; id=&quot;dataGridItems&quot; dataProvider=&quot;{DP}&quot; doubleClickEnabled=&quot;true&quot; doubleClick=&quot;loadURL()&quot; useHandCursor=&quot;true&quot;  backgroundAlpha=&quot;0.4&quot;&gt;
    &lt;mx:columns&gt;
      &lt;mx:DataGridColumn headerText=&quot;Feed entries...&quot; dataField=&quot;title&quot; sortable=&quot;false&quot;/&gt;
     &lt;/mx:columns&gt;
   &lt;/mx:DataGrid&gt;
  &lt;mx:TextInput x=&quot;56&quot; y=&quot;26&quot; width=&quot;227&quot; text=&quot;http://feedproxy.google.com/flashtuts/&quot; height=&quot;20&quot; toolTip=&quot;Click to Edit Feed URL&quot; id=&quot;feedURI&quot; styleName=&quot;myTextInput&quot;/&gt;
 &lt;/mx:Canvas&gt;

&lt;/mx:Application&gt;</pre>
<p>It&#8217;s almost equal right?</p>
<h2>Step 19: Prepare the Application for Web</h2>
<p>Many people will grab the generated WFlexibleFeed.swf from the bin-debug folder and put it in the final production environment, but this is a mistake!</p>
<p>First, use the framework (near 200kb) as RSL (Runtime Shared Library). That will then be downloaded just once to the user&#8217;s machine, next time it will not be loaded (therefore decreasing loading time). To do this, goto Project &gt; Properties &gt; Flex Build Path &gt; Library Path and click on Framework Linkage. Change it from &quot;Merged into code&quot; to &quot;Runtime shared library (RSL)&quot; then click <b>OK</b>. The framework will now be exported as a separated file.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/7.JPG" alt="Framework linkage" width="495" height="231" /></div>
<p>We&#8217;re ready to export the application.</p>
<h2>Step 20: Export Release Build</h2>
<p>Every application should be exported as a release build (that&#8217;s why  project path contains the bin-release folder). You just need to click on the Export Release Build Button, shown yellow here:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/6.JPG" alt="Export Release Build" width="553" height="40" /></div>
<p>The whole project will be exported to the &quot;bin-release&quot; folder. These are the contents to be placed on your site or blog! </p>
<h2>Step 21: Play With It</h2>
<p>You now have time to play with the final result, change some css details, make another kind of feed switcher, there are many things you can improve it. You can even take it to desktop using Adobe AIR. Get inspired! One very nice application for this feedReader is to put your own feed URL, disable text edition, disable the change and refresh buttons and distribute to other sites as a widget to read your blog entries&#8230;</p>
<h2>Conclusion</h2>
<p>In this tutorial you&#8217;ve learned how to parse, handle and display feed entries into a DataGrid inside Flash. You&#8217;ve learned a little about the cool xmlsyndication lib and also dicovered some tricks to improve your projects. Browse the code, download the <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/source.zip" title="Project to import into Flex Builder">source files</a> and have fun!</p>
<p>Note: use the menu File &gt; Import &gt; Flex Project archive to import the source files; they are ready to use!</p>
<p>I hope you liked this tutorial, thanks for reading!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/creating-a-feed-reader-widget-with-adobe-flex-3/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Dynamic Advanced Long Lists with Flex</title>
		<link>http://active.tutsplus.com/tutorials/flex/dynamic-advanced-long-lists-with-flex/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/dynamic-advanced-long-lists-with-flex/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 12:00:04 +0000</pubDate>
		<dc:creator>Jay Leffue</dc:creator>
				<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1120</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/057_FlexDataGrid/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>This tutorial demonstrates how a developer can easily extend the prepackaged Flex library classes to achieve superior user interface results.</p>
<p>In this case, we&#8217;ll be creating an advanced datagrid which can make insanely long lists into manageable chunks and display them as paged lists.  This tutorial deals with primarily AS3, but has a dose of php and mySQL to support back end functionality. The application will be able to store and recall the list&#8217;s shown columns, current page, sort orders and sort fields. Let&#8217;s go..</p>
<p><span id="more-1120"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/057_FlexDataGrid/source.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
  <a href="http://www.jayleffue.com/GridExample.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Introduction</h2>
<p>The datagrid and advanced datagrid classes packaged with Flex are rather limited in functionality. They are only good for very short lists in a real world application. Lists can be millions of lines long and XML documents can&#8217;t be sent representing the full list efficiently. Also, if the XML returned only represents one section of the list, then that is the only section the user will ever see.</p>
<p>This tutorial is the first stage of my own experimentation trying to make advanced datagrids act as the user would intend. Sections of this could be used for a regular DataGrid, but the AdvancedDataGrid is much more usable. The AdvancedDataGrid has a watermark unless you purchase the Professional Edition or if you&#8217;re a student and pick up the education version of FlexBuilder. You will need FlexBuilder, a place to host your php code and a mySQL server for the database to follow this tutorial. I&#8217;m also assuming you&#8217;re competent in basic FlexBuilder functionality like building projects.</p>
<h2>Step 1: Requirements Gathering</h2>
<p>The first step is always to figure out what you want to do. Since all applications are different in their use, your own lists may have different functionality. Based on my user requirements I determined that I needed an application that could:</p>
<ul>
<li>Show data from a list that could be 1 &#8211; &infin; records long. </li>
<li>Allow paging of the data to enhance UI and load times.</li>
<li>Remember the fields being shown.</li>
<li>Remember the fields the list is being sorted on.</li>
<li>Remember the direction those fields are being sorted on (ascending or descending).</li>
<li>Allow the user to change the field order of the grid.</li>
<li>Allow the user to change the page that they are viewing.</li>
</ul>
<h2>Step 2: Determine List Controls</h2>
<p>The user will have all controls built into the AdvancedDataGrid such as multi column sorting and column reordering through dragging the headers. Additionally, the user will have to be able to navigate through the pages of the list. For this, we&#8217;ll need to use a stepper, as well as buttons to allow the user to go to the first page, go to the previous page, reload, go to the next page and go to the last page. Since this cannot be built into the AdvancedDataGrid class itself we must have some kind of container that we create which holds the list we&#8217;ll be working with and all of the controls.</p>
<h2>Step 3: What Are My Events?</h2>
<p>We&#8217;re trying to make the front end as &quot;dumb&quot; as we can. This means that for every action the user makes we must record their actions on the backend. I usually write out a list of everything that must be communicated to my server to help with flow. It also helps for agile development so we can focus on one piece of functionality at a time. For this experiment I determined the following events will need to take place based on the requirements gathered. I&#8217;ve broken this down into two groups; events fired by the list itself and events fired by the controls outside of the list</p>
<p>Outside Events:</p>
<ul>
<li>Page is visited for the first time this session.</li>
<li>Stepper value is changed using the stepper item.</li>
<li>Stepper value is changed using the navigation buttons.</li>
</ul>
<p>List Events:</p>
<ul>
<li>User changes the grid&#8217;s column sorting.</li>
<li>User changes the grid&#8217;s column display order.</li>
<li>Columns are loaded.</li>
<li>List items are loaded.</li>
</ul>
<h2>The Database</h2>
<p>Long lists must come from databases. While there are numerous ways to do this, I have chosen something simple just to get data back to for this experiment. We&#8217;ll need to create a database and two tables. One table for the data we are going to list, and one table as an advanced session variable storage that will make it possible for a list to remember its state as long as the session is valid.</p>
<h2>Step 4: Create Your Tables</h2>
<p>Create two tables. The first is the actual data that we&#8217;ll be retrieving. To make things simple you can simply copy the following to get an exact replica of my test data.</p>
<pre name="code" class="javascript">
CREATE TABLE IF NOT EXISTS `ExampleTable` (
  `RecID` int(10) unsigned NOT NULL auto_increment,
  `Name` varchar(100) NOT NULL,
  `Age` int(11) NOT NULL,
  `School` varchar(100) NOT NULL,
  PRIMARY KEY  (`RecID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=16 ;

INSERT INTO `ExampleTable` (`RecID`, `Name`, `Age`, `School`) VALUES
(1, 'Bugs Bunny', 57, 'Acme U'),
(2, 'Mickey Mouse', 72, 'Disney Community College'),
(3, 'Bart Simpson', 12, 'Springfield Grade'),
(4, 'Peter Griffin', 38, 'Cohog High'),
(5, 'Speedy Gonzalez', 20, 'Univesity of Andale'),
(6, 'Pepe Lepew', 25, 'La Conservatoir National'),
(7, 'Homer Simpson', 39, 'Springfield University'),
(8, 'Raphael', 18, 'Splinter Special Studies'),
(9, 'Splinter', 34, 'The Technodrome'),
(11, 'Donald Duck', 34, 'Naval Academy'),
(12, 'Scrooge McDuck', 65, 'McDougal University'),
(13, 'Papa Smurf', 72, 'Smurf School'),
(14, 'Jabberjaws', 15, 'School Under the Sea'),
(15, 'Quicky Koala', 41, 'Australian State');
</pre>
<p>Now we must create the table to store session information. This is the table that makes this whole thing work.</p>
<pre name="code" class="javascript">
CREATE TABLE IF NOT EXISTS `Session` (
  `RecID` int(10) unsigned NOT NULL auto_increment,
  `SessionID` varchar(32) NOT NULL,
  `Name` varchar(200) NOT NULL,
  `Value` varchar(40960) NOT NULL,
  `LastActiveDTS` timestamp NOT NULL default '0000-00-00 00:00:00' on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`RecID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=37 ;
</pre>
<p> The Session Table has a unique key id, a &#8220;SessionID&#8221; which will be stored as a cookie in PHP, the &#8220;Name&#8221; of the type of information being stored, the &#8220;Value&#8221; stored and a &#8220;LastActiveDTS&#8221; to help with future cleanup to purge old expired sessions. This cleanup is not currently implemented.</p>
<h2>PHP Event Code</h2>
<p>As we determined in Step 3 there are several events that must happen. The following steps go through the php scripts that allow these events to occur on the server. There are many ways to do this, what I have coded works, but even I would not use this in a production environment.</p>
<h2>Step 5: Tag.php</h2>
<p>I created a helper class to help with creating any kind of structured tagged output. This can be used to create html, but in this case it will be the basis for XML. I won&#8217;t go into this code much as I use it as an accessory, more than the point of this tutorial.</p>
<pre name="code" class="javascript">
/**
 * @author     Jay Leffue
 * @version    1.0
 */

/**
* This class is the tag of XML.
*/
class Tag
{
  /**
  * The name of this tag.
  */
  private $_name;

  /**
  * the array of properties to this tag.
  */
  private $_props;

  /**
  * Array of Tags that are direct chilren of this Tag.
  */
  private $_children;

  /**
  * The string content inside this tag.
  */
  private $_content;
  /**
  * class constructor
  *
  * @param    string    $TagName       the name of this tag
  * @param    array     $Attributes    an array of attributes this tag will have
  * @param    string    $Content       content that goes inside this tag.
  * @return   void
  */
  public function __construct($TagName, $Props = null, $Content = null)
  {
    $this-&gt;_name = $TagName;
    $this-&gt;_props = array();
    if(isset($Props))
    {
      $this-&gt;setProps($Props);
    }

    if(isset($Content))
    {
      $this-&gt;_content = $Content;
    }
    $this-&gt;_children = array();

  }

  /**
  * Returns the name used by this Tag.
  *
  * @return string
  */
  public function getName()
  {
    return $this-&gt;_name;
  }

  /**
  * Replaces the current properties for this tag and returns a reference to self.
  *
  * @param  array     $props An array of properties to set for this element.
  *
  * @throws Exception
  * @return Tag
  */
  public function setProps($Props)
  {
    if (!is_array($Props)) throw new Exception('Invalid Properties');

    $this-&gt;_props = $Props;
    return $this;
  }

  /**
  * Adds a specific property for this tag and returns a reference to self.
  * If the property already exists it will replace it.
  *
  * @param  mixed       $Props    An array of properties or if just setting one property a string indicating the name of the property to set.
  * @param  mixed       $Value    If $props is a string this will be the value to set for that property.
  *
  * @throws Exception
  * @return HTMLElement
  */
  public function addProps($Props,$Value=null)
  {
    if (is_array($Props))
    {
      $this-&gt;_props = array_merge($this-&gt;_props,$Props);
    }
    elseif(isset($Value))
    {
      $this-&gt;_props[$Props] = $Value;
    }
    else
    {
      unset($this-&gt;_props[$Props]);
    }
    return $this;
  }

  /**
  * Gets a specific property for this tag.
  *
  * @param     string    $Name    The name of the property to return.
  * @return    mixed
  */
  public function getProp($Name=null)
  {
    if (!isset($Name))
    {
      return $this-&gt;_props;
    }
    elseif(isset($this-&gt;_props[$Name]))
    {
      return $this-&gt;_props[$Name];
    }
    return null;
  }

  /**
  * Returns true if the specified property exists.
  *
  * @param    string    $Name    the name of the property we are searching for.
  *
  * @return boolean
  */
  public function hasProp($Name)
  {
    return array_key_exists($Name,$this-&gt;_props);
  }

  /**
  * Adds child tags to this tag and returns the tag it added.
  *
  * @param  Tag     $Child  The tag to make a child of this Tag.
  * @param  mixed   $Key    Optional value of the array key to assign to this array element
  *
  * @return Tag
  */
  public function addChild(Tag $Child,$Key=null)
  {
    if(isset($Key))
    {
      $this-&gt;_children[$Key] = $Child;
    }
    else
    {
      $this-&gt;_children[] = $Child;
    }
    return $Child;
  }

  /**
  * Looks to see if the tag has an immediate child with the specified name.
  *
  * @param  string     $Name  The Name we are looking for.
  *
  * @return boolean
  */
  public function hasChild($Name)
  {
    foreach($this-&gt;_children as $Child)
    {
      if($Child-&gt;getName() == $Name)
      {
        return true;
      }
    }

    return false;
  }

  /**
  * Returns the children.
  *
  * @param  none.
  *
  * @return array
  */
  public function getChildren()
  {
    return $this-&gt;_children;
  }

  /**
  * Returns the Child Tag with the name specified
  *
  * @param  $string    $Name    the name of the tag we hope to return
  *
  * @return Tag
  */
  public function getChild($Name)
  {
    foreach($this-&gt;_children as $Child)
    {
      if($Child-&gt;getName() == $Name)
      {
        return $Child;
      }
    }
  }

  public function getChildCount()
  {
    return count($this-&gt;_children);
  }

  /**
  * Returns the xml of this tag, if it has children tags, they will be called as well
  *
  * @param none
  *
  * @return string    The resulting XML
  */
  public function getTagXML()
  {
    $string = '';
    //if there are no children then just return the XML tag with embedded '/' at the end
    if(empty($this-&gt;_children))
    {
      if(isset($this-&gt;_content))
      {
        $string .= "&lt;".$this-&gt;_name;
        foreach($this-&gt;_props as $name=&gt;$prop)
        {
          $prop = ereg_replace("'",'',$prop); // Remove single quotes as these appear to be causing issues with fusion charts.
          $string .= " ".$name."='".$prop."'";
        }
        $string .="&gt;".$this-&gt;_content."&lt;/".$this-&gt;_name."&gt;";

      }
      else
      {
        $string .= "&lt;".$this-&gt;_name;
        foreach($this-&gt;_props as $name=&gt;$prop)
        {
          $prop = ereg_replace("'",'',$prop); // Remove single quotes as these appear to be causing issues with fusion charts.
          $string .= " ".$name."='".$prop."'";
        }
        $string .=" /&gt;";
      }
    }
    //otherwise we'll need to dig deeper before closing our tag
    else
    {
      $string.= "&lt;".$this-&gt;_name;
      foreach($this-&gt;_props as $name=&gt;$prop)
      {
        $prop = ereg_replace("'",'',$prop); // Remove single quotes as these appear to be causing issues with fusion charts.
        $string .= " ".$name."='".$prop."'";
      }
      $string .="&gt;";

      //now go through its children
      foreach($this-&gt;_children as $Child)
      {
        $string .= $Child-&gt;getTagXML();
      }
      $string .= "&lt;/".$this-&gt;_name."&gt;";
    }

    return $string;
  }
}</pre>
<h2>Step 6: GetListColumns.php</h2>
<p>This script initializes the session if needed, then returns the columns in the display order and what their sorts are.</p>
<p>First, we make a connection to the database and include our Tag class.</p>
<pre name="code" class="javascript">  require_once('Tag.php');

  //Open communication to the database and table for sessions.
  $con = mysql_connect(&quot;localhost&quot;,&quot;Your Login Name&quot;,&quot;Your Password&quot;);
  if (!$con)
  {
	die('Could not connect: ' . mysql_error());
  }
  mysql_select_db(&quot;Your Database&quot;, $con);
  </pre>
<p>Logically, this is the first event that will be fired when the user first visits the page with the list. Columns must be known before they can be retrieved. With this assumption, the first part of the code deals with initializing the default list options in the Session table and assigning a cookie to this user.</p>
<pre name="code" class="javascript">  //There will be no cookie for session if this is their first time on the page.
  if (!array_key_exists('session',$_COOKIE))
  {
	//Since they do not have a cookie set yet, and this is the first php call, we'll set up some session information for them.
    $_COOKIE['session'] = md5(time());
    setcookie('session',$_COOKIE['session']);

	//There are several items I will set up as defaults here for the list.

	//create the default column order
	mysql_query(sprintf("INSERT INTO Session (SessionID, Name, Value)
	VALUES ('%s', '%s', '%s')",$_COOKIE['session'],'ColumnOrder','Name,Age,School'));

	//create the default column sort, this is a comma delimited string that is one to one with column order
		mysql_query(sprintf("INSERT INTO Session (SessionID, Name, Value)
	VALUES ('%s', '%s', '%s')",$_COOKIE['session'],'SortOrders','Name'));

	mysql_query(sprintf("INSERT INTO Session (SessionID, Name, Value)
	VALUES ('%s', '%s', '%s')",$_COOKIE['session'],'SortDirections','asc'));

	//create the default page for the pager
	mysql_query(sprintf("INSERT INTO Session (SessionID, Name, Value)
	VALUES ('%s', '%s', '%s')",$_COOKIE['session'],'ListPage','1'));
  }</pre>
<p>Now we get the columns to show. We know at this point that we have a session and session variables for this list.</p>
<pre name="code" class="javascript">  //Now it is guaranteed that the user will have a session cookie, as well as the default list at least, so we use the database to
  //determine the column order.
  $dbResult = mysql_query(sprintf("SELECT Value FROM Session WHERE Name = 'ColumnOrder' and SessionID = '%s'",$_COOKIE['session']));

  $return = new Tag('node');
  $columns = $return-&gt;addChild(new Tag('columns'));
  //generic loop
  while($row = mysql_fetch_array($dbResult))
  {
	$columnA = explode(',',$row['Value']);
	foreach($columnA as $column)
	{
		$columns-&gt;addChild(new Tag('column',array('header'=&gt;$column,'data'=&gt;$column,'width'=&gt;'200')));
	}
  }
  mysql_close($con);  

  print('&lt;?xml version="1.0" encoding="UTF-8"?&gt;'.$return-&gt;getTagXML());</pre>
<h2>Step 7: listLoad.php</h2>
<p>This script is what will return the actual data for the DataGrid.</p>
<p>First, we make a connection to the database and include our Tag class.</p>
<pre name="code" class="javascript">require_once('Tag.php');
try
{

  $head = new Tag('items'); 

  //Open communication to the database and table for sessions.
  $con = mysql_connect(&quot;localhost&quot;,&quot;Your Login Name&quot;,&quot;Your Password&quot;);
  if (!$con)
  {
	die('Could not connect: ' . mysql_error());
  }
  mysql_select_db(&quot;Your Database&quot;, $con);	</pre>
<p>We create the query based on values from the session table. Namely, the current page and the sort paramenters needed.</p>
<pre name="code" class="javascript">    //set up how to query based on stored session variables
  //get the start record, assuming 5 records per page.
  $dbResult = mysql_query(sprintf("SELECT Value FROM Session WHERE Name = 'ListPage' and SessionID = '%s'",$_COOKIE['session']));
  $page = (int)mysql_result($dbResult, 0);
  $startRecord = $page*5 - 5;

  //get the sort columns and associate to their direction
  $dbResult = mysql_query(sprintf("SELECT Value FROM Session WHERE Name = 'SortOrders' and SessionID = '%s'",$_COOKIE['session']));
  $order = explode(',',mysql_result($dbResult, 0));

  $dbResult = mysql_query(sprintf("SELECT Value FROM Session WHERE Name = 'SortDirections' and SessionID = '%s'",$_COOKIE['session']));
  $directions = explode(',',mysql_result($dbResult, 0));

  $orderBy = array();
  for($i=0;$i < sizeof($order);$i++)
  {
	$orderBy[] = $order[$i].' '.$directions[$i];
  }

  $query = sprintf('SELECT * FROM ExampleTable ORDER BY %s LIMIT %d,5',implode(',',$orderBy),$startRecord);</pre>
<p>Now that we have created our desired query string, we get the data and return it in XML form. We must also return the ORDER BY parameters so that it can be displayed to the user on the front end.</p>
<pre name="code" class="javascript">    //query the table
  $dbResult = mysql_query($query);
  while($row = mysql_fetch_array($dbResult))
  {
    $item = $head-&gt;addChild(new Tag('item'));
    $item-&gt;addChild(new Tag('id',null,$row['RecID']));
    $item-&gt;addChild(new Tag('Name',null,$row['Name']));
    $item-&gt;addChild(new Tag('Age',null,$row['Age']));
    $item-&gt;addChild(new Tag('School',null,$row['School']));
  }

  $order = $head-&gt;addChild(new Tag('sorts',null,implode(',',$orderBy)));

  mysql_close($con);  

  print('&lt;?xml version="1.0" encoding="UTF-8"?&gt;'.$head-&gt;getTagXML());
}

catch(Exception $e)
{
  print('There was an error that prevented the process from completing.');
}</pre>
<h2>Step 8: stepperMax.php</h2>
<p>This script is needed to determine the maximum number of pages possible for the list. It returns the max pages, as well as the current page for display purposes. For simplicity, the result is a string formatted like &quot;MAX, CURRENT&quot;.</p>
<p>Complete script:</p>
<pre name="code" class="javascript">  //Open communication to the database and table for sessions.
  $con = mysql_connect(&quot;localhost&quot;,&quot;Your Login Name&quot;,&quot;Your Password&quot;);
  if (!$con)
  {
	die('Could not connect: ' . mysql_error());
  }
  mysql_select_db(&quot;Your Database&quot;, $con);	

  //calculate the total number of pages assuming 5 per page.
  $query = sprintf("SELECT COUNT(*) FROM ExampleTable");
  $dbResult = mysql_query($query);
  $totalRecs = (float)mysql_result($dbResult, 0);
  $maxPage = ceil($totalRecs / 5);

  $page=1;
  $dbResult = mysql_query(sprintf("SELECT Value FROM Session WHERE Name = 'ListPage' and SessionID = '%s'",$_COOKIE['session']));
  if($dbResult)
  {
	while($row = mysql_fetch_assoc($dbResult))
	{
		$page = $row['Value'];
	}
  }

  mysql_close($con);  

  print($maxPage.','.$page);</pre>
<h2>Breather</h2>
<p>This wraps up our scripts needed to make the list visible at all. The next php files are solely for updating session information based on user interaction.</p>
<h2>Step 9: stepperUpdate.php</h2>
<p>This is the simple script that changes the value of the &quot;ListPage&quot; session variable. This script is called whenever the stepper of the list is modified by the user. It also assumes there will be a post parameter called &quot;page&quot; sent from the front end application.</p>
<pre name="code" class="javascript">  //Open communication to the database and table for sessions.
  $con = mysql_connect(&quot;localhost&quot;,&quot;Your Login Name&quot;,&quot;Your Password&quot;);
  if (!$con)
  {
	die('Could not connect: ' . mysql_error());
  }
  mysql_select_db(&quot;Your Database&quot;, $con);
  //create the default column order
  $query = sprintf("UPDATE Session SET Value = '%s' WHERE SessionID = '%s' AND Name = 'ListPage'",$_POST['page'],$_COOKIE['session']);

  if(mysql_query($query))
  {
	print("1");
  }
  else
  {
  	print("0");
  }
  mysql_close($con);  </pre>
<h2>Step 10: SetColumnOrder.php</h2>
<p>This is the simple script that changes the value of the &quot;ColumnOrder&quot; session variable. This script is called whenever the user changes the columns around on the front end and it assumes a Post variable named &quot;order&quot;.</p>
<pre name="code" class="javascript">  //Open communication to the database and table for sessions.
  $con = mysql_connect(&quot;localhost&quot;,&quot;Your Login Name&quot;,&quot;Your Password&quot;);
  if (!$con)
  {
	die('Could not connect: ' . mysql_error());
  }
  mysql_select_db(&quot;Your Database&quot;, $con);

  //create the default column order
  $query = sprintf("UPDATE Session SET Value = '%s' WHERE SessionID = '%s' AND Name = 'ColumnOrder'",$_POST['order'],$_COOKIE['session']);

  if(mysql_query($query))
  {
	print("1");
  }
  else
  {
  	print "0";
  }
  mysql_close($con); </pre>
<h2>Step 11: SetSort.php</h2>
<p>This is the simple script that changes the values of the &quot;SortOrders&quot; and &quot;SortDirections&quot; session variables. This script is called whenever the user changes the sorts around on the front end. It assumes a Post variable named &quot;order&quot; and a Post variable named &quot;directions&quot;.</p>
<pre name="code" class="javascript">  //Open communication to the database and table for sessions.
  $con = mysql_connect(&quot;localhost&quot;,&quot;Your Login Name&quot;,&quot;Your Password&quot;);
  if (!$con)
  {
	die('Could not connect: ' . mysql_error());
  }
  mysql_select_db(&quot;Your Database&quot;, $con);

  //create the default column order
  $query = sprintf("UPDATE Session SET Value = '%s' WHERE SessionID = '%s' AND Name = 'SortOrders'",$_POST['order'],$_COOKIE['session']);

  $query2 = sprintf("UPDATE Session SET Value = '%s' WHERE SessionID = '%s' AND Name = 'SortDirections'",$_POST['directions'],$_COOKIE['session']);
  if(mysql_query($query) and mysql_query($query2))
  {
	print("1");
  }
  else
  {
  	print "0";
  }
  mysql_close($con);
</pre>
<h2>/PHP</h2>
<p>That wraps up all the PHP scripts needed to provide for the functionality we want. For ease of use, these files should reside in the same directory as the page that will hold the .swf  and the .swf itself. I didn't go into too much detail as there are many other ways to access a database through php. My final result will most likely only have one php script that is called that can interpret the type of request and has a sort of factory class that determines what should be set or returned. For this example that may have just been overkill. Just remember, we are trying to keep the front end as dumb as we can. The less logic it has to do the better.</p>
<p>Now, finally, we have the backend ready and we can start with Flex.</p>
<h2>Step 12: Set Up Folders in FlexBuilder</h2>
<p>In the src folder of your project create a folder called &quot;css&quot; and a folder called &quot;images&quot;.</p>
<h2>Step 13: Create Images For Stepper Buttons</h2>
<p>You could just use generic buttons, but since vectortuts gave us such a nice selection of icons here : <a href="http://vector.tutsplus.com/articles/web-roundups/60-free-vector-icon-packs-for-design-professionals/">http://vector.tutsplus.com/articles/web-roundups/60-free-vector-icon-packs-for-design-professionals/</a> we can utilize some of these. I used for my example the <a href="http://iconeden.com/icon/milky-a-free-vector-iconset.html">milky icon set</a> to get my arrow buttons. I created the mouse over icons by simply applying a grey screen over the green and saving it as such. The names I used are in the CSS file we'll discuss now. Just remember, we need a total of ten icons; five for the icon, and five matching icons for mouseover events.</p>
<div class="tutorial_image">
<a href="http://vector.tutsplus.com/articles/web-roundups/60-free-vector-icon-packs-for-design-professionals/" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/057_FlexDataGrid/Tutorial/1.jpg" alt=""></a>
</div>
<h2>Step 14: longList.css</h2>
<p>This is my css file for visualization of the list I will be creating.</p>
<pre name="code" class="css">/* CSS file */
.nextButton
{
    up-skin: Embed("images/next.png");
    down-skin: Embed("images/nextover.png");
    over-skin: Embed("images/nextover.png");
    disabled-skin: Embed("images/next.png");
}

.previousButton
{
    up-skin: Embed("images/previous.png");
    down-skin: Embed("images/previousover.png");
    over-skin: Embed("images/previousover.png");
    disabled-skin: Embed("images/previous.png");
}

.lastButton
{
    up-skin: Embed("images/last.png");
    down-skin: Embed("images/lastover.png");
    over-skin: Embed("images/lastover.png");
    disabled-skin: Embed("images/last.png");
}

.firstButton
{
    up-skin: Embed("images/first.png");
    down-skin: Embed("images/firstover.png");
    over-skin: Embed("images/firstover.png");
    disabled-skin: Embed("images/first.png");
}

.reloadButton
{
    up-skin: Embed("images/reload.png");
    down-skin: Embed("images/reloadover.png");
    over-skin: Embed("images/reloadover.png");
    disabled-skin: Embed("images/reload.png");
}</pre>
<h2>Step 15: LongList.as</h2>
<p>Create a new ActionScript class. This class will be our list itself so it extends the AdvancedDataGridClass. I have tried to comment the code as needed so as not to break up the source. By keeping the files at the root we don't have to worry about package paths. In a real world setting I highly advise against doing this as all your script files will need to be organized in different directories. </p>
<p>The key to remember about this class is that we're not really adding much to the library supplied with Flex. All we have to do is give an AdvancedDataGrid the ability to fire events to the server to load information, or change session information. Actual user interface is not changed at all.</p>
<pre name="code" class="javascript">package
{
	//Files to include.
	import flash.events.Event;

	import mx.collections.ArrayCollection;
	import mx.collections.Sort;
	import mx.collections.SortField;
	import mx.collections.XMLListCollection;
	import mx.controls.AdvancedDataGrid;
	import mx.controls.Alert;
	import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
	import mx.events.AdvancedDataGridEvent;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.mxml.HTTPService;

	//Class for lists whos data is very long and can last for several pages of data.
	public class LongList extends AdvancedDataGrid
	{
		//The service that loads the columns
		private var columnService:HTTPService;

		//The service that loads the list data
		private var listService:HTTPService;

		//The service that sets the columns order.
		private var columnOrderService:HTTPService;

		//The service that sets the sorts.
		private var columnSortService:HTTPService;

		//Names of script pages for each of the services.
		private var columnLoadURL:String = "GetListColumns.php";
		private var listLoadURL:String   = "listLoad.php"
		private var columnOrderURL:String   = "SetColumnOrder.php"
		private var columnSortURL:String   = "SetSort.php"

		/* Class constructor.
		*/
		public function LongList()
		{
			//Call the parent constructor
			super();

			this.percentWidth = 100;
			this.height = 150;
			this.horizontalScrollPolicy="on";
			this.verticalScrollPolicy="on";

			//Set up the different service events that can happen.
			columnService = new HTTPService();
			columnService.addEventListener(ResultEvent.RESULT,columnResultHandler);
			columnService.addEventListener(FaultEvent.FAULT ,defaultResultFault);
			columnService.useProxy = false;
			columnService.resultFormat = "e4x";		

			listService = new HTTPService();
			listService.addEventListener(ResultEvent.RESULT,listResultHandler);
			listService.addEventListener(FaultEvent.FAULT ,defaultResultFault);
			listService.useProxy = false;
			listService.resultFormat = "e4x";
			listService.url = this.listLoadURL;	

			columnOrderService = new HTTPService();
			columnOrderService.addEventListener(ResultEvent.RESULT,columnOrderResult);
			columnOrderService.addEventListener(FaultEvent.FAULT ,defaultResultFault);
			columnOrderService.useProxy = false;
			columnOrderService.resultFormat = "text";
			columnOrderService.method = "Post";
			columnOrderService.url = this.columnOrderURL;	

			columnSortService = new HTTPService();
			columnSortService.addEventListener(ResultEvent.RESULT,columnSortResult);
			columnSortService.addEventListener(FaultEvent.FAULT ,defaultResultFault);
			columnSortService.useProxy = false;
			columnSortService.resultFormat = "text";
			columnSortService.method = "Post";
			columnSortService.url = this.columnSortURL;
		}

		/* Function that sends the service to load the columns for the list.
		*/
		public function loadColumns():void
		{
			columnService.url = this.columnLoadURL+'?rand='+Math.random();
			columnService.send();

		}

		/* Function that sends the service to load the list items.
		   This MUST be done after columns have been loaded.
		*/
		public function loadList():void
		{
			listService.url = this.listLoadURL+'?rand='+Math.random();
			listService.send();
		}

		/* The handler for when a result comes back from requesting the columns.
		   I assume the structure of the XML.
		*/
		private function columnResultHandler(event:ResultEvent):void
		{
			this.columns = [];
			var ac:ArrayCollection = new ArrayCollection();

			for each(var item:XML in event.result.columns.children())
			{
				var column:AdvancedDataGridColumn = new AdvancedDataGridColumn();
				column.headerText = item.attribute("header");
				column.dataField  = item.attribute("data");
				column.width      = item.attribute("width");
				ac.addItem(column);
			}

			this.columns = ac.toArray();   

			//now that we know the columns load the list to match.
			this.loadList();
		}

		/* Result handler when a response is returned from the server for a successful column reordering.
		   Nothing needs to be done on the front end unless the response is not a "1" meaning success.
		*/
		private function columnOrderResult(event:ResultEvent):void
		{
			if(event.result.toString() != "1")
			{
				Alert.show("There was an error updating the session variable for this table.");
			}
		}

		/* Result handler when a response is returned from the server when the user wants to sort differently.
		*/
		private function columnSortResult(event:ResultEvent):void
		{
			if(event.result.toString() == "1")
			{
				this.loadList();
			}
			else
			{
				Alert.show("There was an error updating the session variable for this table.");
			}
		}

		/* The handler for when a response (XML) is returned from the server when the current page's list is returned.
		   I assume XML structure based on the PHP code written.
		*/
		private function listResultHandler(event:ResultEvent):void
		{
			var temp:XMLList = event.result.item as XMLList;
			var resultList:XMLListCollection = new XMLListCollection();
			resultList.source = temp;
			resultList.sort = new Sort();
			resultList.sort.fields = new Array;

			//now figure out the sorting.
			//The sort tag will be like "Column Direction, Column2 Direction2, etc"
			var sorter:Sort = new Sort();
			var sorts:String = event.result.sorts;

			//split into an array where each item is the column and that column's direction
			var sArray:Array = sorts.split(',');
			for each(var sortString:String in sArray)
			{
				var iArray:Array = sortString.split(' ');
				var desc:Boolean;
				if(iArray[1] == "desc")
				{
					desc = true;
				}
				else
				{
					desc = false;
				}

				resultList.sort.fields.push(new SortField(iArray[0],true,desc));
			}

			this.dataProvider = resultList;
		}

		/* Handler for when the user clicks on a column header to change the sort parameters for the list.
		   This sends off the service to store the new sorts.
		*/
		protected override function headerReleaseHandler(event:AdvancedDataGridEvent):void
		{
			super.headerReleaseHandler(event);
			var colArray:Array = new Array();
			var dirArray:Array = new Array();

			var sortFields:ArrayCollection = new ArrayCollection(Sort(this.dataProvider.sort).fields);
			for(var i:int;i &lt; sortFields.length;i++)
			{
				colArray.push(sortFields[i].name);
				if(sortFields[i].descending == true)
				{
					dirArray.push("desc");
				}
				else
				{
					dirArray.push("asc");
				}
			}
			var parameter:Object = new Object();
			parameter.order = colArray.toString();
			parameter.directions = dirArray.toString();
			this.columnSortService.request = parameter;
			this.columnSortService.send();				

		}

		/* Handler for when the user lets up the mouse button when they are rearranging the columns.
		   This sends off the service to save the new column order.
		*/
		protected override function columnDraggingMouseUpHandler(event:Event):void
		{
			super.columnDraggingMouseUpHandler(event);

			var columnOrder:Array = new Array();
			for(var i:int;i &lt; this.columns.length;i++)
			{
				columnOrder.push(this.columns[i].dataField as String);
			}		

			this.columnOrderService.request = {order: columnOrder.toString()};
			this.columnOrderService.send();
		}	

		private function defaultResultFault(event:FaultEvent):void
		{
		    Alert.show(event.fault.faultString, "Error");
		}
	}
}</pre>
<h2>Step 16: LongListArea.as</h2>
<p>This is the display container that will have the LongList as well as its controls. For ease I just extended the Panel class and laid everything out inside of it. This class is only concerned with layout of its elements, and what should happen when the user changes the stepper's value be it through the stepper itself or the buttons. Again, to keep it simple I have tried to comment in the code to keep the code all together.</p>
<pre name="code" class="javascript">package
{
	//Necessary files for import.
	import flash.events.MouseEvent;
	import mx.containers.ControlBar;
	import mx.containers.Panel;
	import mx.controls.Alert;
	import mx.controls.Button;
	import mx.controls.NumericStepper;
	import mx.controls.Text;
	import mx.controls.VRule;
	import mx.events.NumericStepperEvent;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.mxml.HTTPService;

	/* This object is the entire control area. Based on the standard Panel Control.
	   This object contains an instance of a LongList, as well as various controls for viewing data of the list.
	*/
	public class LongListArea extends Panel
	{
		//This is the stepper for viewing pages of data
		private var stepper:NumericStepper;

		//A string letting the user know what page they are currently on.  "Page x of XX"
		private var displayed:Text;		

		//A button to take the user back to the first page of data
		private var firstButton:Button;

		//A button to take the user to the last page of data.
		private var lastButton:Button;

		//A button to take the user back one page of data.
		private var previousButton:Button;

		//A button to take the user forward one page of data.
		private var nextButton:Button;

		//A button to reload the current page of data.
		private var reloadButton:Button;

		//The list itself.
		private var list:LongList;

		//A service to update the current page of the list on the server.
		private var stepperService:HTTPService;

		/* Constructor that sets up the different variables associated to the list area
		*/
		public function LongListArea()
		{
			super();
			this.height = 250;
			this.percentWidth  = 80;

			//initialize all the private variables
			displayed = new Text;
			stepperService = new HTTPService();
			stepperService.addEventListener(ResultEvent.RESULT,stepperResultHandler);
			stepperService.addEventListener(FaultEvent.FAULT ,stepperResultFault);
			stepperService.useProxy = false;
			stepperService.resultFormat = "text";
			stepperService.method = "POST";	

			list = new LongList();

			stepper = new NumericStepper();
			stepper.minimum = 1;
			stepper.addEventListener(NumericStepperEvent.CHANGE,handleStepper);

			firstButton = new Button();
			firstButton.styleName="firstButton";
			firstButton.toolTip = "Go to the first page."
			firstButton.id = 'first';
			firstButton.addEventListener(MouseEvent.CLICK,handleButtonClick);

			lastButton = new Button();
			lastButton.styleName = "lastButton";
			lastButton.toolTip = "Go to the last page.";
			lastButton.id = 'last';
			lastButton.addEventListener(MouseEvent.CLICK,handleButtonClick);

			reloadButton = new Button();
			reloadButton.styleName = "reloadButton";
			reloadButton.toolTip = "Reload the current page."
			reloadButton.id = 'reload';
			reloadButton.addEventListener(MouseEvent.CLICK,handleButtonClick);

			previousButton = new Button();
			previousButton.styleName="previousButton";
			previousButton.toolTip="Go to the previous page";
			previousButton.id = 'previous';
			previousButton.addEventListener(MouseEvent.CLICK,handleButtonClick);

			nextButton = new Button();
			nextButton.styleName = "nextButton";
			nextButton.toolTip = "Go to the next page.";
			nextButton.id = 'next';
			nextButton.addEventListener(MouseEvent.CLICK,handleButtonClick);

			//now set up the layout of the Panel.
			addChild(list);
			var control:ControlBar = new ControlBar;
			control.addChild(stepper);
			var ruler:VRule = new VRule();
			ruler.height = 32;
			control.addChild(ruler);
			control.addChild(firstButton);
			control.addChild(previousButton);
			control.addChild(reloadButton);
			control.addChild(nextButton);
			control.addChild(lastButton);
			control.addChild(this.displayed);
			addChild(control);

			//Now we fire off the services to load information about the list and setup the stepper's max and current value.
			//These can be done sequentially this as they are independent of each other.
			loadColumns();
			setStepper();
		}

		/* Sets up and sends the service to load the stepper's max value and current value.
		*/
		private function setStepper():void
		{
			var stepperInit:HTTPService = new HTTPService;
			stepperInit.url = "stepperMax.php?random="+Math.random();
			stepperInit.addEventListener(ResultEvent.RESULT,stepperInitResultHandler);
			stepperInit.addEventListener(FaultEvent.FAULT ,stepperResultFault);
			stepperInit.useProxy = false;
			stepperInit.resultFormat = "text";
			stepperInit.send();
		}

		/* Event Handler for a result from initializing the stepper.
		   Result should be "X,Y" where X=maximum number of pages and Y=Current page.
		*/
		private function stepperInitResultHandler(event:ResultEvent):void
		{
			var temp:Array  = (event.result.valueOf() as String).split(',');
			stepper.value   = temp[1].valueOf();
			stepper.maximum = temp[0].valueOf();

			//Now we can set the string that shows what page the user is on currently.
			displayed.text = 'Page ' + stepper.value + ' of ' + stepper.maximum;
		}

		/* Event Handlers when the user clicks one of the buttons.
		*/
		private function handleButtonClick(event:MouseEvent):void
		{
			switch(event.target.id)
			{
				case "first":
					stepper.value = 1;
					break;
				case "previous":
					if(stepper.value != stepper.minimum)
					{
						stepper.value = stepper.value - 1;
					}
					break;
				case "next":
					if(stepper.value != stepper.maximum)
					{
						stepper.value = stepper.value + 1;
					}
					break;
				case "last":
					stepper.value = stepper.maximum;
					break;
				default:
					break;
			}
			//now that the stepper has been updated, call the function to set it on the backend.
			sendStepperUpdate();
		}

		/* Function that sends the service to update the current page.
		*/
		private function sendStepperUpdate():void
		{
			stepperService.url = "stepperUpdate.php";
			stepperService.request = {page: stepper.value};
			stepperService.send();
		}

		/* Event for when the  stepper value is changed using the stepper itself.
		   Pass through function to sendStepperUpdate
		*/
		private function handleStepper(event:NumericStepperEvent):void
		{
			sendStepperUpdate();
		}

		/* Handler when a result comes back from a stepper request.
		   A response of "1" means the session variable was successfully saved.  Anything else is
		   Considered a fault.
		*/
		private function stepperResultHandler(event:ResultEvent):void
		{
			if(event.result == "1")
			{
				loadList();
				displayed.text = 'Page ' + stepper.value + ' of ' + stepper.maximum;
			}
			else
			{
				Alert.show("There was an error accessing the server.");
			}
		}

		/* Standard fault handler for the stepper.
		*/
		private function stepperResultFault(event:FaultEvent):void
		{
		    Alert.show(event.fault.faultString, "Error");
		}	

		/* Pass through function to element's list.  This will load the contents of the list.
		*/
		public function loadList():void
		{
			list.loadList();
		}

		/* Pass through function to element's list.  This will load the columns of the list.
		*/
		public function loadColumns():void
		{
			list.loadColumns();
		}

		/* Returns the element's list.
		*/
		public function getList():LongList
		{
			return list;
		}
	}
}</pre>
<h2>Step 17: GridExample.mxml</h2>
<p>Since we did all the work in ActionScript the actual mxml markup is super simple. I did it this way to follow OOP principles and to program for reusability. There really is nothing to this file, so here it is.</p>
<pre name="code" class="xml">
&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*"&gt;
&lt;mx:Style source="css/longList.css"/&gt;
	&lt;local:LongListArea/&gt;
&lt;/mx:Application&gt;
</pre>
<h2>Step 18: Wrap Up</h2>
<p>Build your project and put the created files in the same directory as all the php scripts you created. For simplicity, I have them all living at my web root. Try it out, navigate away from the page after you have changed around the page, or the sort, and then come back to it. Hit refresh in your browser. You'll see that the application remembers what you have done!</p>
<h2>Conclusion</h2>
<p>This is just an example of how by simply extending what Flex already has you can achieve very nice results for the user interface. By customizing events you are able to tell Flex what it should be doing and you can use this same methodology to make any list perform as you wish.</p>
<p>I'll be expanding on this hopefully, with added features like a Quick Search, the ability to choose which columns to show, adding columns, removing columns, letting the user Save their selections through the use of a login system, predefined search parameters, predefined list layouts etc. Since Flex is made to be completely extendable there's really no need to have to reinvent the wheel, just make the wheel better! I hope you enjoyed this tutorial.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/dynamic-advanced-long-lists-with-flex/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Build a Multi-Purpose Contact Form With Flex</title>
		<link>http://active.tutsplus.com/tutorials/flex/build-a-multi-purpose-contact-form-with-flex/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/build-a-multi-purpose-contact-form-with-flex/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 12:00:33 +0000</pubDate>
		<dc:creator>Shane Johnson</dc:creator>
				<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=884</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/Tutorial/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>In this tutorial we&#8217;ll be creating a custom Flex-built contact form. We&#8217;ll be implementing many of the fantastic built-in features of the Flex framework, such as the validation methods, the alert box and datefield components to give our contact form added functionality. We&#8217;ll also look into adjusting the CSS properties to give our application a unique look and style.</p>
<p><span id="more-884"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/source.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/preview/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Overview</h2>
<p>We&#8217;re going to be creating a contact form in Flex builder. The reason we&#8217;re using Flex builder over Flash itself, is due to the functionality built into the Flex framework. It&#8217;s easily accessible and would have taken quite a lot of coding to achieve in Flash.  We&#8217;re going to be looking at the validation methods and the alert window available in the Flex framework, as well as many of the components which make using Flex that little bit more special.</p>
<p>For those of you that haven’t downloaded or used Flex Builder yet you can get a trial version from <a href="http://www.adobe.com/cfusion/entitlement/index.cfm?e=Flexbuilder3" target="_blank"> here.</a><br />
If you haven’t used it yet, then best you try and get to grips with using Flex builder and maybe try out some more basic tutorials first.</p>
<h2>Step 1: Let’s Get Started.</h2>
<p>First let’s create a new Flex project by choosing: file &gt; new &gt; Flex project.  Give your project a name; I&#8217;ve chosen ContactForm. We don&#8217;t need to add any extra libraries so leave all of that as default and just click finish.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/Tutorial/1.jpg" alt="" /></div>
<p>Flex builder will now create your project and once it&#8217;s completed you should have the basic Flex project folder structure.</p>
<h2>Step 2: Adding the Components.</h2>
<p>We now want to edit our main mxml class, as we&#8217;re going to be adding a lot of assets to the application.  I usually find this easier in design mode, so if we just switch our workspace over we can get started in creating some visuals.</p>
<p>Firstly we&#8217;re going to add a Panel component to the stage. Make this about 400 x 574 px by adjusting the fields in the layout box on the left hand of the screen:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/Tutorial/2.jpg" alt="" /></div>
<p>We&#8217;re not going to worry too much about how it looks at the moment as we&#8217;re going to be changing this with CSS a little later. We&#8217;re just concentrating on getting the components onto the stage.<br />
We now need to add a few Text input components to the stage; one for each &#8211; first name, surname, email and telephone. I&#8217;ve given each input box a width of 210 pixels and an X value of 130; they are then spaced evenly on the Y axis. We then need to add a Label component to the left of each of these to let the user know what we&#8217;re expecting them to enter and move these all so that they align nicely next to the Text input boxes.</p>
<p>Lastly we&#8217;ll need to give each of our text input boxes a unique id so that they can be targeted with ActionScript. To do this we enter the id in the ID box of the common tab in the Flex properties panel, for my input boxes I&#8217;ve chosen firstName, surName, email and telephone.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/Tutorial/3.jpg" alt="" /></div>
<h2>Step 3: Date Fields and Combo Boxes.</h2>
<p>We now need to add the date field components to the application by dragging the date field component from the component panel to the stage. Once for the &quot;from&quot; date and then again for the &quot;to&quot; date. Again we need to give these a unique id in the id box and I&#8217;ve chosen toDate and fromDate for mine.</p>
<p>We then do the same for the comboBox component. For the comboBox component we also need to tell it where it will be getting its information from to dictate the drop down list produced when the user clicks the comboBox. To do this, in the data provider box for this component in the common tab, we enter {comboText}. What we&#8217;re doing here is telling Flex that as the text is encased in a brace that it should be looking for a variable to provide this information. We are later going to make this variable bindable to the comboBox, so that the swf is constantly looking at this information for any change. </p>
<h2>Step 4: Check Boxes and Radios.</h2>
<p>Lastly we&#8217;ll add two check box components and two radio buttons, along with relevant labels to display the needed information to the user. For these check boxes and radio buttons we need to add a listener via ActionScript to check for  a change in their current state and from which we&#8217;ll pass data to the relevant variable to be saved for the php form. To do this we can enter a function in the onClick box in the common tab. For the purpose of our function we need to pass a parameter into it. In the case of the breakfast check box in the onClick box we would enter the function name with the parameter encased in parenthesis like so: mealsAndCot(breakfast) and for the dinner check box it would be: mealsAndCot(dinner) etc. We&#8217;ll go into more detail on this a little while later.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/Tutorial/4.jpg" alt="" /></div>
<h2>Step 5. Final Touches</h2>
<p>Lastly, we need to add a textArea and give it a relevant ID for the comments box, along with two buttons below it; the reset and the submit button. For the buttons we also need to enter an onClick target function, for the reset button this will be reset() and for the submit button this will be submit(), nice and simple. Now everything on the form has been laid out nicely and has the relevant items have been given and ID for ActionScript referencing. Now let&#8217;s move onto getting the form to look how we want before we move on to the ActionScript.</p>
<h2>Step 6: CSS.</h2>
<p>Applications in Flex builder have the added bonus of being able to be easily changed with simple CSS style sheets. If you right-click on our project root, you can then have an option to go to new &gt; CSS File. This will create a CSS sheet for us to edit. Editing a style sheet in Flex builder is very simple, even if you don’t really understand CSS, as the style sheet is even editable in design mode. To do this with the style sheet opened in Flex builder you can then click on design mode. This will open up the CSS file in design mode which should display a blank screen as the style sheet currently has nothing set in it. To add a setting, click on the button at the top of the screen that looks like a little pile of bricks with a plus sign above it. This will bring up a dialog box which will let us choose a component to add a new style to. Let&#8217;s start with the panel. You&#8217;ll notice a preview of the current setting for the panel.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/039_ContactFormFlex/Tutorial/5.jpg" alt="" /></div>
<p>To the left of this in the properties panel are all of the fields that can be changed. For this tutorial I&#8217;ve chosen to remove the default rounded corners and colour the border black with a 75% opacity. The fill I&#8217;ve changed to a dark grey and changed the text to a light grey in Myriad Pro font. If you click on the category view or the Alphabetical view on the top right of the properties panel you will see that there is a lot more that can be changed so you are not just limited to what is available on the Standard view. You are also able to totally change the skinning of the component by linking it to a swf or swc created in flash or even a png / jpg created in fireworks, Photoshop or illustrator, but that is beyond the remit of this tutorial as we&#8217;re only dealing with the CSS here now.</p>
<h2>Step 7:  CSS Extras</h2>
<p>We only need to change the components that we&#8217;re going to be using in this application. That means the basic components that we have added to the stage already, namely the Text input boxes, labels, the date fields, comboBox and the buttons. The radio buttons and the check boxes are based on the button component so we need not worry about them, however, there are a few hidden components that we do need to worry about.</p>
<p>When we create the validations with ActionScript we&#8217;re also going to be using the Alert window.We therefore need to change the CSS for this, along with the date chooser. The date chooser is the drop down calendar which appears when the user clicks on to the datefield component. However, so that Flex knows that the datefield is using the CSS from our style sheet we need to change a value in the datefield’s CSS. If you change the view in the properties panel to Category view you will see a style called &quot;dateChooserStyle&quot; we need to change this to &quot;contactStyle&quot;, which is the name of our style sheet. Other wise Flex will just use the default grey for the date chooser component.</p>
<p>We also need to do this for the comboBox, whose drop down menu is actually a list component. We link to it by changing the CSS of the list component and the comboBox&#8217;s dropDownStyleName value to the name of our style sheet. Now I&#8217;m not going to go into too much detail about the specifics of the styles I chose for my components in the preview example, except that I&#8217;ve chosen a black / grey colour scheme and made all of my corners sharper with a thin 1 pixel black border. You can set yours however you want and to get an idea of what can be done have a look at the contactStyle.css style sheet also available in the source for this tutorial.</p>
<pre name="code" class="css">
/* CSS file */
Panel
{
	controlBarStyleName: panelControlBar;
	titleStyleName: panelTitle;
	fontSize: 12;
	fontWeight: normal;
	fontFamily: "Arial";
	borderColor: #010101;
	borderAlpha: 0.75;
	borderThicknessLeft: 10;
	roundedBottomCorners: false;
	cornerRadius: 0;
	borderThicknessRight: 10;
	backgroundColor: #5C5B5B;
	color: #DDDEDE;
	backgroundSize: auto;
}
DateField
{
	fontFamily: "Arial";
	borderColor: #1A1A1A;
	dateChooserStyleName: contactStyle;
}
TextArea
{
	backgroundColor: #9B9A9A;
	borderColor: #131313;
}
ScrollBar
{
	borderColor: #3C3D3D;
	trackColors: #363737, #818383;
	fillAlphas: 1.0, 1.0, 1.0, 1.0;
	fillColors: #9B9A9A, #413E3E, #9B9A9A, #393838;
	cornerRadius: 0;
}
DateChooser
{
	backgroundColor: #3B3939;
	headerColors: #313132, #313132;
	color: #E2E6E7;
	borderThickness: 1;
	borderColor: #1A1A1A;
	cornerRadius: 0;
	fontFamily: "Arial";
	fontSize: 12;
}
Button
{
	cornerRadius: 0;
	borderColor: #5B5C5C;
	fillAlphas: 1.0, 1.0;
	fillColors: #9F9E9E, #3F3E3E;
	color: #C3CACB;
	textRollOverColor: #B9BCBF;
	fontFamily: "Arial";
	fontWeight: normal;
}
TextInput
{
	backgroundColor: #9B9A9A;
	borderColor: #1C1D1D;
	borderThickness: 1;
	borderStyle: solid;
}
ComboBox
{
	fontFamily: "Arial";
	fontWeight: normal;
	cornerRadius: 0;
	dropDownStyleName: contactStyle;
}
List
{
	backgroundColor: #676565;
	borderColor: #202020;
	fontFamily: "Arial";
	color: #DBDDDE;
}
Label
{
	fontFamily: "Arial";
	fontSize: 12;
}
Alert
{
	borderColor: #151515;
	backgroundColor: #939292;
	backgroundSize: auto;
}
.panelTitle
{
	fontFamily: "Arial";
}
@font-face
{
	fontFamily: "Arial";
	fontWeight: normal;
	fontStyle: normal;
	src: local("Arial");
}
@font-face
{
	fontFamily: "Arial";
	fontWeight: normal;
	fontStyle: normal;
	src: local("Arial");
}
</pre>
<h2>Step 8: Linking the CSS to Our Application.</h2>
<p>Now that we&#8217;ve styled our style sheet we need to tell our application to adopt this look. This is very simple and we do it by adding this bit of code to our mxml class:</p>
<pre name="code" class="xml">
&lt;mx:Style source=&quot;contactStyle.css&quot;&gt;
&lt;/mx:Style&gt;
</pre>
<p>Now if you go back into design view and check out the application, as long as everything has been done correctly you will see that the components have all changed according to the CSS style sheet.</p>
<h2>Step 9: Let’s Get Coding!</h2>
<p>OK, so now that we have things looking how we want them, it&#8217;s time to add some functionality to our contact form and this is all done with the magic of ActionScript. Back into source mode, let’s add a script block to our application by typing:</p>
<pre name="code" class="xml">
  &lt;mx:Script&gt; 

  &lt;/mx:Script&gt;</pre>
<p>Thankfully, with Flex we don&#8217;t need to add any import statements. By default it adds them for us as we go along, so we can start by creating the relevant variables. We need one variable to hold the information for the check boxes, an Array which we&#8217;ll call meals, then another variable for the cot radio buttons. As these buttons are labelled yes or no, we&#8217;ll make this variable a Boolean so that it returns true or false. We also need to create an instance of the Alert class, so that we can manipulate it later during the submit function. Finally we need to add the variable which will hold the information for our comboBox as defined earlier. This we&#8217;ll call comboText, it will be an Array and as mentioned earlier we make this variable bindable by adding the keyword &quot;bindable&quot; before declaring the variable.</p>
<pre name="code" class="javascript">	private var alertWindow:Alert;
	private var meals:Array = [];
	private var cot:Boolean = false;

	[Bindable]

	private var comboText:Array = [{label: &quot;King sized room&quot;},
                				 {label: &quot;Double room&quot;}];
</pre>
<h2>Step 10: Passing Radio and Check Box Data.</h2>
<p>Our next function will pass the data from the radio and check boxes into usable information. In creating these components we gave them an onClick listener and into this we passed a parameter which as you can see from the function itself was an &quot;object&quot;. During this function we check to see what this object is via an &quot;if&quot; statement and through that, manipulate our data. In this case we have an array for the meal requirements into which we push information, or for the check box we have a Boolean which is set to true for the yes check box or false for the no check box.</p>
<pre name="code" class="javascript">	private function mealsAndCot(object:Object):void
			{
				if(object == breakfast){
					meals.push(&quot;breakfast, &quot;);
				}
				else if(object == dinner){
					meals.push(&quot;dinner, &quot;);
				}
				else if(object == yesCot){
					cot = true;
				}
				else{
					cot = false;
				}
			}
</pre>
<p>This data can then be sent to our php script during the submitToPHP function once everything has been checked by the submit function next.</p>
<h2>Step 11: Validation.</h2>
<p>Now it is time to pull in the built in validation methods from the Flex framework, and we do this similarly to creating a new components. Firstly we&#8217;re going to create an instance of the mx:stringValidator to check and validate the first name and surname.  To do this for the first name validation check we type the below text ,below the application node outside of the mx:script tags:</p>
<pre name="code" class="xml">
&lt;mx:StringValidator id = &quot;validFirstName&quot; source=&quot;{firstName}&quot; property=&quot;text&quot;/&gt;
</pre>
<p>As you can see the parameters needed for the validator are an id, and a source to be checked,  in this case the firstName. We do the same by creating a validator to check the surname. For the email and telephone number we do the same but, Flex has other validators, namely email validator and number validator that can be used nicely for these fields, so the script below our main application tag should look like so:</p>
<pre name="code" class="xml">
&lt;mx:StringValidator id = &quot;validFirstName&quot; source=&quot;{firstName}&quot; property=&quot;text&quot;/&gt;
&lt;mx:StringValidator id =  &quot;validSurName&quot; source=&quot;{surName}&quot; property=&quot;text&quot;/&gt;
&lt;mx:EmailValidator id =  &quot;validEmail&quot; source=&quot;{email}&quot; property=&quot;text&quot;/&gt;
&lt;mx:NumberValidator id = &quot;validPhone&quot; source=&quot;{telephone}&quot; property=&quot;text&quot;/&gt;
</pre>
<h2>Step 12: The Submit Function.</h2>
<p>The main meat of our application is the submit function. This is called when the user clicks on the submit button to send the entered text and information through the contact form.<br />
As in this function we&#8217;re going to be checking the entered text and needed fields, we start off by creating instantiations of the ValidationResultEvent. Rather than calling it here as an event listener, we&#8217;re going to say that its equal to the result of  the validation check carried out by the Validator itself. We of course create one of these instantiations for each of the validation checks and then pass the results to &quot;if&quot; statements to create the event carried out depending on the result.</p>
<pre name="code" class="javascript">	private function submit():void
			{
				var firstNameValidation:ValidationResultEvent = validFirstName.validate();
				var surNameValidation:ValidationResultEvent = validSurName.validate();
				var emailValidation:ValidationResultEvent = validEmail.validate();
				var phoneValidation:ValidationResultEvent = validPhone.validate();
				if(firstNameValidation.type == ValidationResultEvent.INVALID || surNameValidation.type == ValidationResultEvent.INVALID){
					Alert.show(&quot;You must enter a valid name&quot;);
				}
				else if(emailValidation.type == ValidationResultEvent.INVALID){
					Alert.show(&quot;Please enter a valid email address&quot;);
				}
				else if(phoneValidation.type == ValidationResultEvent.INVALID){
					Alert.show(&quot;Please enter a valid phone number&quot;);
				}
				else if(comments.text == &quot;&quot;){
					Alert.show(&quot;Please enter a message&quot;);
				}
				else{
					submitToPHP();
				}
			}.
</pre>
<h2>Step 13: The Alert Box.</h2>
<p>As you can see from the function, we&#8217;re passing each validation check to an &quot;if&quot; statement and using the INVALID ValidationResultEvent rather than VALID to create an Alert box by calling the function Alert.show(). If you&#8217;ve ever programmed with Javascript you&#8217;ll be well aware of the alert window which you can use to create a pop up box alerting the user of the browser with a button to click which usually says &quot;OK&quot;. As you are all users of various web browsers, you will all be familiar with the alert box. The Alert class in the Flex framework is exactly the same and is a nice bit of functionality that we can use simply by calling the Alert.show function. The parameters needed for this are simply the string to be shown in the alert box itself.</p>
<p>Of course, if all of the input data is entered correctly and doesn’t match any of the conditions, we then move on to the submitToPHP function.</p>
<h2>Step 14: Submitting the Data to PHP.</h2>
<p>Now that all of the entered data has been checked we can pass the information to a PHP script to mail to the recipient.  The PHP script we&#8217;re using is a simple send mail script which passes all the information gathered into a plain text message, but there is nothing stopping you creating a full html message, by using the variable passed here.</p>
<p>To pass this info to our PHP script we first create an instance of the URLVariable class here called variables, into which we pass all of the information gathered. We then create a URLRequest in this case called phpUrl, which is aimed at the php script&#8217;s location. We then pass the URLVariable to the URLRequest by using:</p>
<pre name="code" class="javascript">
	phpUrl.data = variables;
</pre>
<p>As you can see, when passing the data from the input boxes and other components on the application we simply assign the text in that box to the relevant variable asset. With the meal Array, we simply pass this with the toString() method to create a string from the array itself. We then create a URLLoader to send all of this data to the relevant URL and then add a listener to listen out for completion of the transition or for any errors in sending to display the relevant message in the alert box which will pop up. </p>
<pre name="code" class="javascript">
	private function submitToPHP():void
			{
				var variables:URLVariables = new URLVariables();
				var phpUrl:URLRequest = new URLRequest("http://www.ultravisual.co.uk/Test/sendform.php");
				phpUrl.method = URLRequestMethod.GET;
				phpUrl.data = variables;

				variables.firstname_text = firstName.text;
				variables.surname_text = surName.text;
				variables.email_text = email.text;
				variables.phone_text = telephone.text;
				variables.comment_text = comments.text;
				variables.room_text = comBo.text;
				variables.datefrom_text = fromDate.text;
				variables.dateto_text = toDate.text;
				variables.meals = meals.toString();
				variables.cot = cot;

				var loader:URLLoader = new URLLoader();
				loader.dataFormat = URLLoaderDataFormat.TEXT;
				loader.addEventListener(Event.COMPLETE, completeHandler);
				try{
					loader.load(phpUrl);
					alertWindow = Alert.show("Sending........");
				}
				catch(error:Error){
					Alert.show("Error sending form.");
				}
			}
</pre>
<h2>Step 15: Complete.</h2>
<p>In the try statement during the last function you can see that rather than just using Alert.show(), we&#8217;ve created an instance of the Alert class and used it to create the pop up. The reason for this is that in the complete function we need to close this box in order to display our success message in the next function. If we don’t create an instance of the Alert class for this, flash will just create another alert box and overlay it on top of our last one, rather than closing any existing ones. As you can see, we close the existing alert box by using:</p>
<pre name="code" class="javascript">
	PopUpManager.removePopUp(alertWindow);
</pre>
<p>We can then use Alert.show() to display a new alert box which will wait for user interaction. We then use the reset function described below to reset the contact form back to its original state.</p>
<h2>Step 16: The Reset Function.</h2>
<p>Having made our buttons, we now have two functions that need to be created, namely reset and submit. This function is also called on completion of the sendToPHP function. Reset will basically reset the contact form back to its base state by clearing the boxes and any text. This will also be called once the contact form has been completed and the information has been sent to the PHP script. The reset function is very simple:</p>
<pre name="code" class="javascript">
	private function resetForm():void
		{
			firstName.text = "";
			surName.text = "";
			comBo.selectedIndex = -1;
			telephone.text = "";
			email.text = "";
			comments.text = "";
			fromDate.text = "";
			toDate.text = "";
			noCot.selected = false;
			yesCot.selected = false;
			breakfast.selected = false;
			dinner.selected = false;
		}
</pre>
<p>This just tells the swf that the text to be displayed for each of the text fields is equal to nothing and that none of the radio buttons or check boxes are selected and so should be displayed as so.</p>
<h2>Conclusion</h2>
<p>As you can see, using the validation methods and the alert box in Flex is very simple as well as using the functionality of many of the components. For more information on any of the Flex components and methods more information can be gathered by looking at the <a href="http://livedocs.adobe.com/Flex/3/langref/" target="_blank">adobe reference pages for Flex.</a> Thanks for following along!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/build-a-multi-purpose-contact-form-with-flex/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Build an XML Driven Contact List Using Flex 3</title>
		<link>http://active.tutsplus.com/tutorials/flex/build-an-xml-driven-contact-list-using-flex-3/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/build-an-xml-driven-contact-list-using-flex-3/#comments</comments>
		<pubDate>Fri, 03 Apr 2009 12:00:57 +0000</pubDate>
		<dc:creator>Zach Dunn</dc:creator>
				<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=116</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/004_flexContactList/preview.jpg" alt="" />]]></description>
			<content:encoded><![CDATA[<p>The goal in this tutorial is to built a contact list which loads dynamically from an external XML file. When the user selects a different contact, the data will automatically update to display properly. We&#8217;ll also be applying some basic stylesheet changes to the results and give the project a more customized touch.</p>
<p><span id="more-116"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/004_flexContactList/srcview/index.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/004_flexContactList/Preview/contact-list-flex.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h3>Final Result Preview</h3>
<p>Let&#8217;s take a look at a screenshot of the final result we will be working towards:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/004_flexContactList/1.jpg" alt="Complete Contact List" /></div>
<p><em>Note: As you’ll quickly realize, I do not use the SDK to build Flex 3 files. While this tutorial is taught from the perspective of the Flex 3 Builder, the underlying code is the same. SDK users, you’ll simply have to substitute steps as needed. I won’t be using the design view in this tutorial, so you’re in luck.</em></p>
<h2>Step 1 &#8211; Free for Education</h2>
<p>Flex is a great development platform. It&#8217;s better when you have the full <a href="http://www.adobe.com/products/flex/" title="Flex 3 Builder">Flex 3 Builder</a>. Lucky for eligible students and faculty, Adobe is offering a full Education Flex 3 Builder license to you for free</p>
<p>Consider this a friendly reminder. If anyone with educational ties has yet to take advantage of the “<a href="https://freeriatools.adobe.com/flex/">Free Flex 3 for Education</a>” deal yet, go ahead and do that now. It’ll help you out <em>enormously</em>.</p>
<p>Now that we&#8217;re finished with the &#8220;free Adobe product&#8221; evangelism, let&#8217;s build a Flex application!</p>
<h2>Step 2 &#8211; Set Up Project Files</h2>
<p>Start by creating a new Flex project for the web. Name it whatever you&#8217;d like, this step will not have an impact on the results.</p>
<p>Within the project, start a new MXML Application (File &gt; New &gt; MXML Application). Name the file &#8220;contactManager&#8221;.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/004_flexContactList/2.jpg" alt="Layout Setup" /></div>
<p>For layout purposes, I recommend changing the layout default to &#8220;vertical&#8221;. This will center all immediate child components on the page, which will work much better with our end goal.</p>
<h2>Step 3 &#8211; Download Images</h2>
<p>Each contact will display a profile picture when selected. For this example, we will be using Bill Gates and Barack Obama as contacts. <a href="http://www.apple.com/pr/photos/execs/jobsphotos.html">Steve Jobs&#8217; press photo was just too terrible</a></p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/004_flexContactList/3.jpg" alt="Contact Profile Pictures" /></div>
<p>I&#8217;ve cropped their press photos (retrieved <a href="http://www.microsoft.com/presspass/exec/billg/default.aspx?tab=images">here</a> and <a href="http://change.gov/newsroom/entry/new_official_portrait_released/">here</a>) to smaller dimensions for this tutorial. <a href="http://flashtuts.s3.cdn.plus.org/004_flexContactList/contact-images.zip">Grab the edited versions here</a>, and we&#8217;ll move onto the XML file.</p>
<h2>Step 4 &#8211; Introducing the XML File</h2>
<p>All of the information displayed will be pulled from an external XML file. The basic structure is as follows:</p>
<pre name='code' class='xml'>
&lt;userlist&gt;
	&lt;user&gt;
		&lt;name&gt;Bill Gates&lt;/name&gt;
		&lt;position&gt;Head Nerd&lt;/position&gt;
		&lt;email&gt;bill@microsoft.com&lt;/email&gt;
		&lt;image&gt;images/gates.jpg&lt;/image&gt;
	&lt;/user&gt;
&lt;/userlist&gt;
</pre>
<p>As you can see, there are four main fields for each entry. The contact name, their position, email, and url to a profile image.</p>
<p><a href="http://flashtuts.s3.cdn.plus.org/004_flexContactList/user-data.xml">Download the file</a>, and we&#8217;ll be ready to arrange all of the files you&#8217;ve downloaded into asset folders for Flex.</p>
<h2>Step 5 &#8211; Arrange Project File Structure</h2>
<p>Make sure your project files are arranged as in the image below. You will need to make the folder &#8220;assets&#8221; for user-data.xml, and an &#8220;images&#8221; folder for the profile shots (File &gt; New &gt; Folder with &#8220;src&#8221; folder selected).</p>
<p>Import the files downloaded in step 4 and 5 into their corresponding folders. With the target folder selected, select File &gt; Import &gt; Other and use the prompt to select a file. Rinse and repeat for each until you&#8217;ve got all three in place.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/004_flexContactList/4.jpg" alt="Directory" /></div>
<h2>Step 6 &#8211; Make Request for XML File</h2>
<p>In Flex MXML, external files are most commonly loaded in with the HTTPService tag. Think of it like preparing an envelope to mail. It contains a target destination and includes instructions for what to do with the contents.</p>
<p>Create a HTTPService tag to request our XML file by entering the following tag immediately under the opening application tag.</p>
<pre name='code' class='xml'>
		&lt;mx:HTTPService url="assets/user-data.xml" id="userData" result="contentHandler(event)" resultFormat="e4x"/&gt;
	</pre>
<p>This HTTPService has an ID of &#8220;userData&#8221; and loads our user-data xml file. The resulting data is formatted as E4X and passed to the contentHandler function we will be making shortly for processing.</p>
<p>Take note however, because <em>simply making a HTTPService tag does not send the request</em>. Just like an envelope needs a mailbox to travel, the HTTPService request must be actually sent.</p>
<h2>Step 7 &#8211; Send Request on CreationComplete</h2>
<p>In order for this request to be sent, we must activate it once the project successfully loads. We do this using the creationComplete event in the application tag.</p>
<pre name='code' class='xml'>
		&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()"&gt;
	</pre>
<p>While we could just directly insert the userData.send() method here, we&#8217;re going to use a more expandable function init() to send the request instead. This function will be responsible for actions fired once the Flex project loads, and opens up the possibility for multiple load events. We&#8217;ll fill in the contents of this function during a later step.</p>
<h2>Step 8 &#8211; Set Up for Actionscript</h2>
<p>The actionscript of this project will be responsible for handling the loaded XML file, storing filters, and updating components as needed. This will be accomplished with three separate functions.</p>
<p>Remember that <em>Flex is a framework for actionscript</em>, much like jQuery is to JavaScript. This means that even though Flex tags are designed to streamline common actionscript usages, it can also handle direct scripting as well. For this, we&#8217;ll need to designate an area for the scripting to go.</p>
<p>And this is where the Script tag comes into play. Insert the tag directly below the opening Application tag. This is where all actionscript will be written; kept separate from the MXML below. If you&#8217;re in the Builder, the tag will automatically add the CDATA markup:</p>
<pre name='code' class='xml'>
	&lt;mx:Script&gt;
		&lt;![CDATA[
			//actionscript goes here.
		]]&gt;
	&lt;/mx:Script&gt;
	</pre>
<p>We&#8217;ll start by importing the ResultEvent package that is required for the HTTPService tag. (Remember that all the code in this section goes between the script tags mentioned above)</p>
<pre name='code' class='xml'>import mx.rpc.events.ResultEvent;</pre>
<h2>Step 9 &#8211; Declare Variables</h2>
<p>In order to build XML filters, we&#8217;ll need to define some variables. Both with be defined as bindable, which allows us to directly link the contents to a Flex component (e.g. Label).</p>
<pre name='code' class='xml'>
	//Holds complete XML raw file content
	[Bindable] private var userList:XMLList;

	//Changes to Selected Contact's XML Data
	[Bindable] private var selectedData:XML;
	</pre>
<p>The userList XML List will contain the E4X formatted results from the loaded XML file. We will use it to populate the data grid component in a later step.</p>
<p>The selectedData XML variable will hold the currently selected result in the data grid component. It will be responsible for populating the information fields and profile image.</p>
<h2>Step 10 &#8211; Build the init Function</h2>
<p>The init() function that we referenced in the last step will do two things.</p>
<ol>
<li>Send the request for the user data XML file.</li>
<li>Set the name label (yet to be created) to a default &#8220;No Contact Selected&#8221; text</li>
</ol>
<p>The code below will accomplish both. Ignore any warnings about nonexistent components for now, we&#8217;ll be creating the referenced label in the next step.</p>
<pre name='code' class='xml'>
	//Creation Complete Events
	private function init():void{
		userData.send();
		profileName.text = "No Contact Selected";
	}
	</pre>
<h2>Step 11 &#8211; Build the contentHandler Function</h2>
<p>The next function is the contentHandler called by the result event of the HTTPService tag. This function takes the passed event, and then assigns the userList XML List variable the resulting XML data as filtered to the &#8220;user&#8221; level.</p>
<pre name='code' class='xml'>
	private function contentHandler(evt:ResultEvent):void{
		userList = evt.result.user;
	}
	</pre>
<h2>Step 12 &#8211; Build the showProfile Function</h2>
<p>The last function (showProfile) is activated when a name is selected from the contact list. It simply assigns the contents of the currently selected XML entry to the variable selectedData. This is the variable that will be bound to the labels and image containers for live updates.</p>
<pre name='code' class='xml'>
	private function showProfile(evt:Event):void{
		//Assign data to currently selected item
		selectedData = contactList.selectedItem as XML;
	}
	</pre>
<p>Now that the actionscript is in place, we&#8217;re ready to put together the design.</p>
<h2>Step 13 &#8211; Block out the Layout</h2>
<p>The contact list layout will consist of a series of HBox and VBox containers (horizontal and vertical respectively). The block out below illustrates the structure of the final design.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/004_flexContactList/5.jpg" alt="Block Layout" /></div>
<h2>Step 14 &#8211; Create Layout Components</h2>
<p>All of this content we&#8217;ve loaded in will need a home. That&#8217;s where the layout&#8217;s components come in. Paste in the following structure below the HTTPService tag.</p>
<pre name='code' class='xml'>
	&lt;mx:HBox&gt;

		&lt;mx:VBox height="490"&gt;
			&lt;mx:DataGrid id="contactList" width="400"&gt;
				&lt;mx:columns&gt;
					&lt;mx:DataGridColumn headerText="Contact Name"/&gt;
				&lt;/mx:columns&gt;
			&lt;/mx:DataGrid&gt;

			&lt;mx:Label fontSize="24" id="profileName"/&gt;
			&lt;mx:Label id="profileJob"/&gt;
			&lt;mx:Label id="profileEmail"/&gt;
		&lt;/mx:VBox&gt;	

		&lt;mx:VBox width="360"&gt;
			&lt;mx:Image id="profilepic"/&gt;
		&lt;/mx:VBox&gt;					

	&lt;/mx:HBox&gt;
	</pre>
<p>MXML has a nice advantage of being relatively simple to read. The only component that may be throwing someone new to Flex off is the Data Grid. Essentially the data grid is a table. The columns tag between the DataGrid tag specify the header text and fields for individual columns.</p>
<p>These are the components that will be used to load data from the XML file. In the next step, we&#8217;ll populate each with the relevant data.</p>
<h2>Step 15 &#8211; Populate the Components</h2>
<p>Patching in the data from the XML entries is surprisingly simple. Copy in the following code changes, and meet back below for a summary.</p>
<pre name='code' class='xml'>
	&lt;mx:HBox&gt;
		&lt;mx:VBox height="490"&gt;
			&lt;mx:DataGrid id="contactList" width="400" change="showProfile(event)" dataProvider="{userList}"&gt;
				&lt;mx:columns&gt;
					&lt;mx:DataGridColumn dataField="name" headerText="Contact Name"/&gt;
				&lt;/mx:columns&gt;
			&lt;/mx:DataGrid&gt;

			&lt;mx:Label fontSize="24" id="profileName" text="{selectedData.name}"/&gt;
			&lt;mx:Label id="profileJob" text="Position: {selectedData.position}"/&gt;
			&lt;mx:Label id="profileEmail" text="Email: {selectedData.email}"/&gt;
		&lt;/mx:VBox&gt;	

		&lt;mx:VBox width="360"&gt;
			&lt;mx:Image id="profilepic" source="{selectedData.image}"/&gt;
		&lt;/mx:VBox&gt;					

	&lt;/mx:HBox&gt;
	</pre>
<p>Here&#8217;s a breakdown of what&#8217;s going on:</p>
<ol>
<li>The data grid is populated by binding the userList XML list to it. The column loads the data field &#8220;name&#8221; from each entry.</li>
<li>When the selected item on the data grid changes, it calls the showProfile function to update the selectedData XML.</li>
<li>The labels are each set to display a field of the selected entry.</li>
<li>In the right column, the image containers source is loaded from the url in the XML file.</li>
</ol>
<h2>Step 16 &#8211; Change the Background Colors</h2>
<p>If you work with Flex for a while, it&#8217;s easy to become sick of the default color scheme. Let&#8217;s make some quick fixes to spice things up.</p>
<p>We&#8217;ll start by changing the background to a gradient in blacks. Update your opening application tag to include the gradient properties below:</p>
<pre name='code' class='xml'>
	&lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#212121, #010101]"&gt;
	</pre>
<p>The downside of a black background is that none of the default text will be visible. We&#8217;ll fix this by using Flex&#8217;s CSS to change font colors.</p>
<h2>Step 17 &#8211; Style the Results</h2>
<p>Did you know that Flash and Flex support their own brand of CSS? We&#8217;ll be using some basic formatting to improve the readability of this application. Start by inserting a style tag directly below the opening Application tag.</p>
<pre name='code' class='xml'>
	&lt;mx:Style&gt;
		/*CSS goes here*/
	&lt;/mx:Style&gt;
	</pre>
<p>The CSS offered in Flex is limited, but we can still make effective visual changes. In the CSS below, I&#8217;ve changed all the labels to a white font for readability. The HBox containing everything has been given a black background and padding of 20px on each side for spacing.</p>
<pre name='code' class='xml'>
	&lt;mx:Style&gt;

			Label{
				color:#FFF;
			}

			HBox{
				backgroundColor:#010101;
				paddingTop:20;
				paddingLeft:20;
				paddingRight:20;
				paddingBottom:20;
			}

	&lt;/mx:Style&gt;
	</pre>
<p><em>*Note that you must capitalize the component names in the CSS in order for it to reference properly.</em></p>
<h2>Step 18 &#8211; Source Code for Project</h2>
<p>If you haven&#8217;t fallen in love with Flex yet, this next feature may push you over the edge. Flex makes sharing a project&#8217;s source code not only easy, but really good looking. <a href="http://flashtuts.s3.cdn.plus.org/004_flexContactList/srcview/index.html">Take a look at the results, in a surprisingly browser-friendly design</a>.</p>
<h2>Step 19 &#8211; Conclusion &amp; Further Applications</h2>
<p>What you should have now is a XML driven contact list in Flex. Give it a test run and make sure everything is in working order.</p>
<p>Flex, as the name implies, is incredibly flexible. This means that you can take the framework from the tutorial above, and continue to add on. The data grid component will expand as needed.</p>
<p>Flex has a large variety of transitional effects, such as blur and resize, that can be applied on each change. The results of this tutorial could be a great place to start experimenting with more visual options such as these.</p>
<p>Go ahead and experiment! If you come up with any cool additions, be sure to share them with us in the comments.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/004_flexContactList/1.jpg" alt="Complete Contact List" /></div>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/build-an-xml-driven-contact-list-using-flex-3/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.660 seconds -->
