Sunday, January 14, 2007

Implementing a Remote File Explorer in Flex 2: List View

The first application I want to implement in Flex is a standard split-pane file explorer, with a folder tree in the left pane and a list of folder contents in the right pane.

A basic implementation of the list pane turned out to be very simple:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  creationComplete="initApp(); itemsService.send();">

  <mx:Script source="explorer.as"/>

  <mx:HTTPService id="itemsService" url="/flex/items.jsp" 
    resultFormat="e4x" showBusyCursor="true"
    fault="handleFault(event)">
    <mx:request>
      <folderID>{folderID}</folderID>
    </mx:request>
  </mx:HTTPService>

  <mx:XMLListCollection id="itemsList" 
      source="{itemsService.lastResult.item}"/>

  <mx:DataGrid id="itemGrid" width="100%" height="100%" 
 dataProvider="{itemsList}">
    <mx:columns> 
      <mx:DataGridColumn dataField="title" headerText="Title"/>
      <mx:DataGridColumn dataField="size" headerText="Size"/>
      <mx:DataGridColumn dataField="type" headerText="Type"/>
      <mx:DataGridColumn dataField="lastModified" headerText="Last Modified"/>
    </mx:columns>
  </mx:DataGrid>
</mx:Application>

Working from the bottom of the file up:

4. The DataGrid is a scrollable, sortable table component. Viewers can resize and reposition columns by dragging the column headers.

3. The XMLListCollection is the data source for the table. Flex automatically updates the table when the data source changes.

2. The HTTPService defines how to retrieve data from the server as a simple XML document, in this case returned by a JSP. Flex automatically unmarshals the XML into the data source whenever it receives a successful response. The request element defines the dynamic query parameters that should be added to each request.

3. The Script references a small bit of ActionScript to handle initialization and request faults:

import mx.controls.Alert;
import mx.rpc.events.FaultEvent;

[Bindable]
public var folderID:String;

private function initApp():void {
  folderID = Application.application.parameters.folderID;
}

private function handleFault(e:FaultEvent):void {
  Alert.show("Failed to contact the server.");
}

The XML document returned by the server corresponds to the rows and columns in the table:

<items>
  <item>
    <title>myscript.as</title>
    <size>10.1K</size>
    <type>ActionScript</type>
    <lastModified>8:34 AM 01/15/07</lastModified>
  </item>
  ...
</items>

The only other thing I had to do was modify the wrapper HTML page to pass a folder ID to Flex:

<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <title>File Explorer</title>
      <script src="AC_OETags.js" language="javascript"></script>
      <style>
 body { margin: 0px; overflow:hidden }
      </style>
  </head>

  <body scroll='no'>
    <script language="JavaScript" type="text/javascript">
      <!--
      AC_FL_RunContent(
      "src", "explorer",
      "width", "100%",
      "height", "100%",
      "align", "middle",
      "id", "flexstore",
      "quality", "high",
      "bgcolor", "#869ca7",
      "name", "explorer",
      "flashVars", "folderID=<%=folderID%>",
      "allowScriptAccess","sameDomain",
      "type", "application/x-shockwave-flash",
      "pluginspage", "http://www.adobe.com/go/getflashplayer"
 );
      // -->
    </script>
    <noscript>
      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
 id="flexstore" width="100%" height="100%"
 codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
 <param name='flashVars' value='folderID=<=folderID%>'></param>
 <param name="movie" value="explorer.swf"></param>
 <param name="quality" value="high"></param>
 <param name="bgcolor" value="#869ca7"></param>
 <param name="allowScriptAccess" value="sameDomain"></param>
 <embed src="explorer.swf" quality="high" bgcolor="#869ca7"
   width="100%" height="100%" name="flexstore" align="middle"
   flashVars="folderID=<%=folderID%>"
   play="true"
   loop="false"
   quality="high"
   allowScriptAccess="sameDomain"
   type="application/x-shockwave-flash"
   pluginspage="http://www.adobe.com/go/getflashplayer">
 </embed>
      </object>
    </noscript>
  </body>
</html>

I compiled the MXML file and was able to view the file list in the browser. Very nice!