Kalen Gibbons: The Dead Treetag:www.kalengibbons.com,2009:/blog/A blog by Kalen Gibbons, covering Flex, ColdFusion, and other web technologies.Mango 1.2.4Filtering a Flex Tree using an ArrayCollectionurn:uuid:ADD90F11-3048-78A9-77653A7FCE3789F92009-01-06T09:01:38Z2009-01-06T10:01:00ZKalen Gibbons
<p>Flex Trees can be difficult to filter because of their hierarchical nature. One possible way to do it is to use an ArraryCollection as your dataProvider, with each node having a "children" property that is also an ArrayCollection.</p>
<p>The tricky part in filtering the Tree is making sure the children are filtered in addition to the root nodes. So, in the example below, I have created a function that will loop through each node and its children recursively. </p>
<p>It is important to note that the filtering takes place from the bottom up, meaning that a node's children are always filtered before the node itself. This is important, because normally a filter removes everything that does not match a certain criteria. In our case, to remain in the collection, a node must match a certain criteria OR have children that do.</p>
<div class="asCode">
<?xml version="1.0" encoding="utf-8"?><br />
<span class="mxmlComponent"><mx:Application</span> xmlns:mx="<span class="asString">http://www.adobe.com/2006/mxml</span>"
<div class="indent">layout="<span class="asString">absolute</span>"<span class="mxmlComponent">></span></div>
<div class="indent">
<span class="mxmlSpecialString">
<br />
<mx:Script></span>
<div class="indent">
<![CDATA[<br />
<span class="asReserved">import</span> vo.Person;<br />
<span class="asReserved">import</span> mx.collections.ArrayCollection;<br />
<br />
[<span class="asReserved">Bindable</span>]<br />
<span class="asReserved">private</span> <span class="asVar">var</span> people:ArrayCollection = <span class="asReserved">new</span> ArrayCollection([
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">Grandma Susan</span>", <span class="asReserved">new</span> ArrayCollection([<br />
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">John</span>", <span class="asReserved">new</span> ArrayCollection([<br />
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">Timmy</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Sammy</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Alan</span>")</div>
])),<br />
<span class="asReserved">new</span> Person("<span class="asString">Tiffany</span>", <span class="asReserved">new</span> ArrayCollection([<br />
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">Billy</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Adam</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Graham</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Vennesa</span>")</div>
])),<br />
<span class="asReserved">new</span> Person("<span class="asString">Michael</span>", <span class="asReserved">new</span> ArrayCollection([<br />
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">Jannette</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Alan</span>", <span class="asReserved">new</span> ArrayCollection([<br />
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">Alice</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Jane</span>")</div>
])) </div>
])),<br/>
<span class="asReserved">new</span> Person("<span class="asString">Peter</span>"),<br />
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">Cindy</span>", <span class="asReserved">new</span> ArrayCollection([<br />
<div class="indent">
<span class="asReserved">new</span> Person("<span class="asString">Paul</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">David</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Joseph</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Cameron</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Debra</span>"),<br />
<span class="asReserved">new</span> Person("<span class="asString">Polly</span>")<br />
</div>
</div>
]))</div>
])) </div>
]);<br />
<br />
<span class="asReserved">private</span> <span class="asFunction">function</span> refreshData():<span class="asReserved">void</span>{<br />
<div class="indent">
<span class="asComment">//reset the root node to its original unfiltered data</span><br />
people[0].children = <span class="asReserved">new</span> ArrayCollection(people[0].children.source);<br />
<span class="asComment">//start the recursion at the root node</span><br />
refreshRecursiveChildren(people.source[0]);<br />
<span class="asComment">//update the Tree after the data has been filtered</span><br />
personsTree.invalidateList();</div>
}<br />
<br />
<span class="asReserved">private</span> <span class="asFunction">function</span> refreshRecursiveChildren(person:Person):<span class="asReserved">void</span>{<br />
<div class="indent">
<span class="asReserved">if</span>(person.children){<br />
<div class="indent">
<span class="asComment">//loop through each child and filter its children</span><br />
<span class="asReserved">for each</span>(<span class="asVar">var</span> _person:Person <span class="asReserved">in</span> person.children.source){<br />
<div class="indent">refreshRecursiveChildren(_person);</div>
}<br />
<span class="asComment">//reset each "children" ArrayCollection to its original unfiltered data</span><br />
person.children = <span class="asReserved">new</span> ArrayCollection(person.children.source);<br />
<span class="asComment">//set the filterfunction for the newly updated node</span><br />
person.children.filterFunction = filterData;<br />
<span class="asComment">//run the fitlerFunction</span><br />
person.children.refresh(); </div>
} </div>
}<br />
<br />
<span class="asReserved">public</span> <span class="asFunction">function</span> filterData(item:Object):Boolean{<br />
<div class="indent">
<span class="asComment">//get the string to filter the nodes by</span><br />
<span class="asVar">var</span> searchString:String = iNameFilter.text;<br />
<span class="asComment">//if string is found in node return true.<br />
//since the recursive filtering takes place from bottom up, if<br />
//a collection still has children after filtering, also return true</span><br />
<span class="asReserved">if</span>(searchString.length == 0 <div class="indent">|| item.name.toLowerCase().indexOf(searchString.toLowerCase()) >= 0)<br />
<span class="asReserved">return true</span>;</div>
<span class="asReserved">else if</span>(item.children != <span class="asReserved">null</span> && item.children.length > 0)<br />
<div class="indent"><span class="asReserved">return true</span>;</div>
<br />
<span class="asReserved">return false</span>;</div>
}<br />
]]></div>
<span class="mxmlSpecialString"></mx:Script></span><br />
<br />
<span class="mxmlComponent"><mx:VBox</span> width="<span class="mxmlString">100%</span>" height="<span class="mxmlString">100%</span>"<br />
<div class="indent4">
paddingTop="<span class="mxmlString">10</span>"<br />
paddingBottom="<span class="mxmlString">10</span>"<br />
paddingLeft="<span class="mxmlString">5</span>"<br />
paddingRight="<span class="mxmlString">5</span>"<span class="mxmlComponent">></span><br />
</div>
<div class="indent">
<span class="mxmlComponent"><mx:Tree</span> id="<span class="mxmlString">personsTree</span>"<br />
<div class="indent4">
dataProvider="<span class="mxmlString">{people}</span>"<br />
labelField="<span class="mxmlString">name</span>"<br />
width="<span class="mxmlString">100%</span>"<br />
height="<span class="mxmlString">100%</span>" <span class="mxmlComponent">/></span></div>
<span class="mxmlComponent"><mx:HBox></span><br />
<div class="indent">
<span class="mxmlComponent"><mx:Label</span> text="<span class="mxmlString">Filter the Tree:</span>" <span class="mxmlComponent">/></span><br />
<span class="mxmlComponent"><mx:TextInput</span> id="<span class="mxmlString">iNameFilter</span>" change="<span class="mxmlString">refreshData()</span>" <span class="mxmlComponent">/></span></div>
<span class="mxmlComponent"></mx:HBox></span></div>
<span class="mxmlComponent"></mx:VBox>
</span>
</div>
<span class="mxmlComponent"></mx:Application></span><br />
</div>
<div style="text-align: center">
<br/><br/>
You may right-click and select "View Source" <br/>
to view the full source code for the following example.<br/>
<iframe id="filteringTreeFrame" height="560" width="400" src="/assets/pages/treefiltering.html" frameborder="0" scrolling="no"></iframe>
</div>
Tour de Flex: An amazing learning toolurn:uuid:899C3312-3048-78A9-77B62A1F6D7198382008-12-30T01:12:19Z2008-12-30T01:12:00ZKalen Gibbons
<p>If you haven't checked out <a title="Tour de Flex" href="http://flex.org/tour" target="_blank">Tour de Flex</a> I suggest you do. It is an Air app that contains over 200 working applications, all with source code. Everything from simple Flex components to advanced filters and working with Air is covered, so there's something for everyone, beginners to advanced developers alike.</p>
<style type="text/css">
#tourdeflex body{
background-color: #000000;
color: #FFFFFF;
}
</style>
<div style="text-align: center">
<iframe id="tourdeflex" width="215" height="180" frameborder=0 scrolling="no" src="http://tourdeflex.adobe.com/badge/"></iframe>
</div>
Christmas presents from Kap Laburn:uuid:65937E1E-3048-78A9-77D013188E71833C2008-12-23T01:12:16Z2008-12-23T01:12:00ZKalen Gibbons
<p>Just in time for Christmas, <a title="Kap Lab" href="http://lab.kapit.fr/display/kaplabhome/Home" target="_blank">Kap Lab</a> has released version
1.1.0 of its data visualization components.<span>
</span>In addition, two new developer tools have been released: the <a title="Kap Lab - Cairngorm Console" href="http://lab.kapit.fr/display/cairngormconsole" target="_blank">Cairngorm
Console</a> and the <a title="Kap Lab - PureMVC Console" href="http://lab.kapit.fr/display/puremvcconsole" target="_blank">PureMVC Console</a>.<span> </span>All Kap
Lab’s components are free and are extremely useful.<span> </span>I suggest you give them a look.</p>
<ul>
<li><a title="Kap Lab - Visualizer" href="http://lab.kapit.fr/display/visualizer/Visualizer" target="_blank">Visualizer</a></li>
<li><a title="Kap Lab - Diagrammer" href="http://lab.kapit.fr/display/diagrammer/Diagrammer" target="_blank">Diagrammer</a></li>
<li><a title="Kap Lab - Ring Chart" href="http://lab.kapit.fr/display/ringchart" target="_blank">Ring Chart</a></li>
<li><a title="Kap Lab - Radar Chart" href="http://lab.kapit.fr/display/radarchart/Radar+Chart" target="_blank">Radar Chart</a></li>
<li><a title="Kap Lab - Treemap" href="http://lab.kapit.fr/display/treemap/treemap" target="_blank">Treemap</a><br /></li>
<li><a title="Kap Lab - Kap Inspector" href="http://lab.kapit.fr/display/kapinspect/Kap%20Inspect" target="_blank">Kap Inspector</a></li>
<li><a title="Kap Lab - Cairngorm Console" href="http://lab.kapit.fr/display/cairngormconsole" target="_blank">Cairngorm Console</a></li>
<li><a title="Kap Lab - PureMVC Console" href="http://lab.kapit.fr/display/puremvcconsole" target="_blank">PureMVC Console</a><br /></li>
</ul>
<p> </p>
Displaying DataTips when using an itemRendererurn:uuid:8827AE7F-3048-78A9-771A49282608D0192008-12-13T01:12:28Z2008-12-13T04:12:00ZKalen Gibbons
<p>One of the bad things about using itemRenderers in a DataGridColumn is that you lose the dataTip functionality that it normally provides. Well, here is a way to fake that functionality.</p>
<p>First, add the dataTipField or dataTipFunction to the DataGridColumn like you normally would.</p>
<div class="asCode">
<span class="mxmlComponent"><mx:DataGridColumn</span> headerText="<span class="mxmlString">DataTip</span>"<br />
<div class="indent6">
<div class="indent">
dataField="<span class="mxmlString">name1</span>"<br />
showDataTips="<span class="mxmlString">true</span>"<br />
dataTipField="<span class="mxmlString">description1</span>" <span class="mxmlComponent">/></span>
</div>
</div>
</div>
<p>Then, in your itemRenderer add the following code to be able to tap into that information and display a tooltip instead.</p>
<div class="asCode">
<span class="asReserved">private</span> <span class="asFunction">function</span> getToolTip():String{<br />
<div class="indent">
<span class="asVar">var</span> dg:DataGrid = listData.owner <span class="asReserved">as</span> DataGrid;<br />
<span class="asVar">var</span> func:Function = dg.columns[listData.columnIndex].dataTipFunction;<br />
<br />
<span class="asReserved">if</span>(func != <span class="asReserved">null</span>){<br />
<div class="indent">
<span class="asReserved">return</span></span> func.call(<span class="asReserved">this</span>, <span class="asReserved">this</span>.data);</div>
}<span class="asReserved">else if</span>(dg.columns[listData.columnIndex].dataTipField.length){<br />
<div class="indent">
<span class="asReserved">return</span> data[dg.columns[listData.columnIndex].dataTipField];</div>
}<span class="asReserved">else</span>{<br />
<div class="indent">
<span class="asReserved">return</span> <span class="asString">""</span>;</div>
}</div>
}
<br />
<br />
<span class="asReserved">override protected</span> <span class="asFunction">function</span> updateDisplayList(unscaledWidth:Number,<br />
<div class="indent6"><div class="indent6"><div class="indent3">unscaledHeight:Number):<span class="asReserved">void</span>{</div></div>
</div>
<div class="indent">
<span class="asReserved">super</span>.updateDisplayList(unscaledWidth, unscaledHeight);<br />
<span class="asReserved">this</span>.toolTip = getToolTip();</div>
}
</div>
<p>This works with both dataTipFields and dataTipFunctions and lets you treat the dataTips in your columns the same way, regardless of whether you're using an itemRenderer or not. The only minor difference is the positioning of the label, but that can be easily modified with styles. You can download the <a href="/assets/files/psuedoDataTips.zip">full source code here</a>, for a functional example of how this works.</p>
<center>
<iframe height="200" frameborder="0" width="670" src="/assets/pages/psuedoDataTips.html"></iframe>
</center>
<p> </p>
Update: Solution to disappearing data in your itemRendererurn:uuid:EC0DC5EA-3048-78A9-77CFC9EDB3BE0D972008-12-08T08:12:00Z2008-12-08T10:12:00ZKalen Gibbons
<p>In a <a title="Disappearing data in your itemRenderer?" href="/blog/post.cfm/disappearing-data-in-your-itemrenderer" mce_href="/blog/post.cfm/disappearing-data-in-your-itemrenderer" target="_self">previous post</a> I explained how a rendering bug in Flex was causing items to disappear in an itemRenderer. In the example below, you can see that when you scroll, the items in the list disappear. This is caused by the varying heights of the elements. If you explicitly set the height for each element or set variableRowHeights to false, then the problem goes away.</p>
<center>
<iframe height="230" frameborder="0" width="310" src="/assets/pages/itemRenderer1.html"></iframe>
</center>
<br/>
<p>What was causing the problem was apparent but the solution was not. Thankfully, Olivier Lalonde was nice enough to shed some light on an easy fix. The itemRenderer needs to be validated as the user scrolls. So, as Olivier suggests, you simply need to listen for the dataChange event and execute the validateNow() function.</p>
<p>You can see in the example below that the list now has varying row heights... and the data no longer disappears. NICE! The key point to focus on here is the following line: <mx:VBox <span style="font-weight: bold;" mce_style="font-weight:bold">dataChange="validateNow()"</span> verticalGap="0"></p>
<div class="asCode">
<span class="mxmlComponent"><mx:List</span>
dataProvider="<span class="mxmlString">{</span>myData.item<span class="mxmlString">}</span>"<br>
<div class="indent">
variableRowHeight="<span class="mxmlString">true</span>"<br>
alternatingItemColors="<span class="mxmlString">['#FFFFFF','#E6EEF3']</span>"<br>
width="<span class="mxmlString">100%</span>"<br>
height="<span class="mxmlString">100%</span>"<span class="mxmlComponent">></span><br><br>
<span class="mxmlComponent"><mx:itemRenderer></span><br>
<div class="indent">
<span class="mxmlSpecialString"><mx:Component></span><br>
<div class="indent">
<span class="mxmlComponent"><mx:VBox</span> verticalGap="<span class="mxmlString">0</span>" dataChange="validateNow()"<span class="mxmlComponent">></span><br>
<div class="indent">
<span class="mxmlComponent"><mx:HBox></span><br>
<div class="indent">
<span class="mxmlComponent"><mx:Label</span> text="<span class="mxmlString">{</span>data.Label<span class="mxmlString">}</span>" fontWeight="<span class="mxmlString">bold</span>" <span class="mxmlComponent">/></span><br/>
<span class="mxmlComponent"><mx:Label</span> text="<span class="mxmlString">{</span>data.date<span class="mxmlString">}</span>" color="<span class="mxmlString">#999999</span>" <span class="mxmlComponent">/></span>
</div>
<span class="mxmlComponent"></mx:HBox></span><br>
<span class="mxmlComponent"><mx:Text</span> text="<span class="mxmlString">{</span>data.description<span class="mxmlString">}</span>" width="<span class="mxmlString">100%</span>" <span class="mxmlComponent">/></span><br>
</div>
<span class="mxmlComponent"></mx:VBox></span><br>
</div>
<span class="mxmlSpecialString"></mx:Component></span><br>
</div>
<span class="mxmlComponent"></mx:itemRenderer></span><br><br>
</div>
<span class="mxmlComponent"></mx:List></span>
</div>
<br/>
<center>
<iframe height="230" frameborder="0" width="400" src="/assets/pages/itemRenderer3.html"></iframe>
<center>
<br/>
<p></p>
Clearing framework RSLs from your Flash Player cacheurn:uuid:B634E247-3048-78A9-77E710A89B97CA012008-11-29T09:11:41Z2008-11-29T11:11:00ZKalen Gibbons
<p>Runtime Shared Libraries (RSLs) are a good way to reduce the size of your Flex applications. A framework RSL, for example, is an external version of the Flex framework that can be stored in the user's Flash Player cache. The great thing about this is that when a user downloads the RSL the first time it is stored in cache, and no matter what domain it was downloaded from, it can be used by all other Flex applications on the web. The framework RSL is never downloaded again, meaning that your application doesn't need to contain any of the Flex framework code, thus reducing the size of your core application.</p>
<p>But this caching can also cause some difficulties while testing. If you are creating a new application that will use an RSL, you will need to specify the path to it in your build options (of course, this local copy will only be referenced by users who don't already have the RSL in their cache). Well, how do you know if this path is accurate if you already have the RSL in your cache? When you test your application it will not try to access your local RSL if you already have it in cache. </p>
<p>So what you need to do is clear out your Flash Player cache. To do this, go to <a title="Flash Player Settings Manager" href="http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager03.html" target="_blank">http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager03.html</a> and uncheck "Store common Flash components to reduce download time." When the pop-up box appears, click "Confirm" and your Flash Player cache will be cleared. </p>
<p style="text-align:center"><img style="border: 0; margin: 0px;" src="/assets/images/flashPlayerSettingManager.gif" alt="Flash Player Setting Manager" width="395" height="270" /></p>
<p>Now that your cache is cleared you may re-check the box to restore your setting and turn caching back on. When you test your application for the first time it will require the framework to load from the RSL path you specified. You’ll know you have a problem if your application fails and gives you a message about unresolved RSL paths. </p>
<p>I prefer to keep caching turned off while testing, to get a better feel for what users will experience on their first visit to the application. However, don't forget to turn it back on after you're done testing.</p>
How to drag, drop, and parse a CSV file in AIRurn:uuid:CB41DBAD-3048-78A9-773D91CE037E05D72008-11-26T08:11:12Z2008-11-30T01:11:00ZKalen Gibbons
<p><img style="float: left; border: 0; margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 15px;" src="/assets/images/csvDrag.png" alt="Drag and Drop a CSV file in Adobe AIR" width="80" height="84" />I've been playing around with Adobe AIR lately and I've really been enjoying it. So I thought I'd put out this quick tutorial on how to drag and drop a file into your AIR application; in this case we will be using a CSV file, and then we will parse that file so that its data can be used in a datagrid. You can <a title="Download source files" href="/assets/files/CSVDragandDrop.zip" target="_blank">download the full source code here</a>.</p>
<h3 class="accentBold">Dragging a file into AIR:</h3>
<p>First, we need to set up handlers to listen for the drag events. We are going to set up two listeners, one for when an item is dragged over the app and one for when that item is dropped.</p>
<p class="asCode">
<span class="asReserved">this</span>.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, dragEnterHandler);<br />
<span class="asReserved">this</span>.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, dragDropHandler);
</p>
<p>Then we'll set up the two handler function. The dragEnterHandler function determines if the item is an acceptable file type. You could use the different constants of the <a title="Flex 3 Clipboard class" href="http://livedocs.adobe.com/flex/3/langref/flash/desktop/Clipboard.html" target="_blank">ClipboardFormats</a> class to only accept specific file formats, but for now we will accept any valid file.</p>
<div class="asCode">
<span class="asReserved">private</span> <span class="asFunction">function</span> dragEnterHandler(evt:NativeDragEvent):<span class="asReserved">void</span>{<br />
<div class="indent">
<span class="asReserved">if</span>(evt.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT)){<br />
<div class="indent">
NativeDragManager.acceptDragDrop(<span class="asReserved">this</span>);<br />
</div>
}<br />
</div>
}<br />
</div>
<p>Next, when the user drops the file, we will copy it from the clipboard, read its contents, and parse its values into a more usable data structure.</p>
<div class="asCode">
<span class="asReserved">private</span> <span class="asFunction">function</span> dragDropHandler(evt:NativeDragEvent):<span class="asReserved">void</span>{<br />
<div class="indent">
NativeDragManager.dropAction = NativeDragActions.COPY;<br />
<span class="asComment">//get an array of the files dropped in</span><br />
<span class="asVar">var</span> dropFiles:Array = evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) <span class="asReserved">as</span> Array;<br />
<span class="asComment">//get the content of the file</span><br />
<span class="asVar">var</span> fileContent:String = getFileContent(dropFiles[0]);<br />
<span class="asComment">//parse it to get an array of Orders</span><br />
orders = parseCSV(fileContent);<br />
</div>
}<br />
</div>
<p> </p>
<h3 class="accentBold">Reading the content of the dropped file:</h3>
<p>For this we will use the <a title="Flex 3 FileStream class" href="http://livedocs.adobe.com/flex/3/langref/flash/filesystem/FileStream.html" target="_blank">FileStream</a> class. The getFileContent function takes a generic file as its only parameter; it opens a FileStream, reads the contents of the file and returns that value as a string.</p>
<div class="asCode">
<span class="asReserved">private</span> <span class="asFunction">function</span> getFileContent(_file:File):String{<br />
<div class="indent">
<span class="asComment">//open a fileStream to read the content of the file</span><br />
<span class="asVar">var</span> fileStream:FileStream = <span class="asReserved">new</span> FileStream();<br />
fileStream.open(_file, FileMode.READ);<br />
<span class="asVar">var</span> fileContent:String = fileStream.readUTFBytes(fileStream.bytesAvailable);<br />
fileStream.close();<br />
<span class="asReserved">return</span> fileContent;<br />
</div>
}<br />
</div>
<p> </p>
<h3 class="accentBold">Parsing the CSV file:</h3>
<p>Finally, we are going to take the content of the CSV file, which is now in the form of a string, and parse out its data to populate an Array. We start by using the split() function to create an Array of line items. We use character code 10, which represents carriage returns, and character code 13, which represents new lines. to separate each line item. Then we loop through the newly created array of line items and pull out each comma separated value. At this point we have the information we need to populate the Order object and add that to our Array.</p>
<div class="asCode">
<span class="asReserved">private</span> <span class="asFunction">function</span> parseCSV(_content:String):Array{<br />
<div class="indent">
<span class="asComment">//create temporary array to store the Orders</span><br />
<span class="asVar">var</span> csvArray:Array = <span class="asReserved">new</span> Array();<br />
<span class="asComment">//break the csv into individual lines</span><br />
<span class="asVar">var</span> csvLines:Array = _content.split(String.fromCharCode(13,10));<br />
<span class="asComment">//remove title row</span><br />
csvLines.splice(0,1);<br />
<span class="asComment">//loop over each line</span><br />
<span class="asReserved">for each</span>(<span class="asVar">var</span> s:String <span class="asReserved">in</span> csvLines){<br />
<div class="indent">
<span class="asVar">var</span> lineItems:Array = s.split(<span class="asString">","</span>);<br />
<span class="asVar">var</span> transaction:Order = <span class="asReserved">new</span> Order( lineItems[0],<br />
<div class="indent6">
<div class="indent5">
<span class="asReserved">new</span> Date(lineItems[1]),<br />
lineItems[2],<br />
lineItems[3],<br />
lineItems[4]);<br />
</div>
</div>
csvArray.push(transaction);<br />
</div>
}<br />
<span class="asReserved">return</span> csvArray;<br />
</div>
}<br />
</div>
<p>The data pulled from the CSV file is now in a more manageable form and can be used as a dataProvider for components or to populate AIR's built in SQLite database. Of course, in this tutorial, for simplicity's sake, we assume that the file dropped into the application is a CSV file. In your application you should have some trapping to determine the file type and process it accordingly.</p>
My Flex workshop for the IECFUGurn:uuid:92890345-3048-78A9-77D7EF344E732B112008-11-14T09:11:14Z2008-11-14T10:11:00ZKalen Gibbons
<p>I recently presented a short beginner's workshop for the <a title="Inland Empire ColdFusion User Group" href="http://www.iecfug.com/" target="_blank">The Inland Empire ColdFusion User Group</a>. In the workshop we created a simple application that displayed hypothetical tracking data. Through this application we covered many basic Flex topics and techniques, and I thought I would provide the files for anyone who wants them. <a title="Download tracker.zip" href="/assets/files/tracker.zip">Download them here</a>.</p>
<p style="text-align:center"><a title="Tracker Application" href="/assets/pages/tracker_styles.html" target="_self"><img src="/assets/images/iecfug-tracker.gif" alt="Tracker Styles Application" width="600" height="393" /></a></p>
<p>Here is a list of files you'll find the in ZIP folder, and a brief summary for each:</p>
<ol>
<li class="accentBold">tracker_start.mxml - <a title="Tracker Start" href="/assets/pages/tracker_start.html" target="_blank">view</a>
<ul>
<li>This is where to get started. With only 2 lines of mxml code, we create an application that displays all our data to the user. Pretty cool! The sample XML data has been provided for you in the data folder.<br /></li>
</ul>
</li>
<li class="accentBold">tracker_filters.mxml - <a title="Tracker Filters" href="/assets/pages/tracker_filters.html" target="_blank">view</a>
<ul>
<li>This is the second file in the workshop. Now that we are displaying the data to the user, we need to make it more usable. We want to make it easy for users to find the information they are looking for. So, in this step we use the ArrayCollection's built in filterFunction capabilities to allow the user to easily and effeciently filter through the data. </li>
</ul>
</li>
<li class="accentBold">tracker_charts.mxml
<ul>
<li>This is a charting component that will be used in the next step, the tracker_states application. It charts the popularity of all the processes in our data.</li>
</ul>
</li>
<li class="accentBold">tracker_states.mxml - <a title="Tracker States" href="http://kalengibbons.com/assets/pages/tracker_states.html" target="_blank">view</a>
<ul>
<li>The third application in the workshop, in which we create a second state. In this new state we add the tracker_charts component, giving users an alternative representation of the data.<br /></li>
</ul>
</li>
<li class="accentBold">tracker_styles.mxml - <a title="Tracker Styles" href="/assets/pages/tracker_styles.html" target="_blank">view
</a>
<ul>
<li>The final step, in which we turn our bland, boring application into something more presentable. All we do in this step is add a wonderful theme from <a title="ScaleNine: Skins and Themes for Flex and AIR" href="http://www.scalenine.com/" target="_blank">ScaleNine</a>. <br /></li>
</ul>
</li>
<li class="accentBold">tracker_remoting.mxml
<ul>
<li>This file does not
actually create a viewable application, it is just a reference file.
It is an example of how Flex can connect to ColdFusion; an alternative to using the Model data that we used in the preceeding applications.</li>
</ul>
</li>
<li class="accentBold">data folder<br />
<ul>
<li>Contains the XML data used in all applications.<br /></li>
</ul>
</li>
<li class="accentBold">assets folder<br />
<ul>
<li>Includes the theme that was used in the tracker_styles application.</li>
</ul>
</li>
</ol>
<p> </p>
<p>Copy the files into the src folder of your project and give it a crack. I hope you find them useful.</p>
<p> </p>
Best Optical Illusion... EVER!urn:uuid:2D29C8D3-3048-78A9-77F87971073A727D2008-10-23T09:10:40Z2008-10-23T10:10:00ZKalen Gibbons
<p>I'm a big fan of optical illusions. I love how your eyes and your mind don't always agree on things, and this is a great illustration of that. </p>
<p>In the picture below, square A and square B are the exact same color. You may find this hard to believe; I still do when I look at it, but it's true. To prove it, take any image program or a colorpicker, like <a href="http://www.iosart.com/firefox/colorzilla/" target="_blank">ColorZilla</a>, and compare the colors. ColorZilla shows that both cells are the color #787878. Furthermore, I took this image into PhotoShop, cut out square B and overlapped it over square A... guess what? They match. <a href="/assets/pics/opticalIllusion2.gif" target="_blank">Click here to see the results.</a></p>
<p style="text-align: center;"><img style="border: 5px ridge #FFFFFF" src="/assets/pics/opticalIllusion1.png" alt="Optical Illusion" width="507" height="395" /></p>
<p>Can you get your eyes to see the truth?</p>
Disappearing data in your itemRenderer?urn:uuid:0E1BD0FB-3048-78A9-77674D73F4347D722008-10-14T08:10:00Z2008-12-09T01:12:00ZKalen Gibbons
<p class="notice">Note: An update to this post has been posted <a href="http://www.kalengibbons.com/blog/post.cfm/update-solution-to-disappearing-data-in-your-itemrenderer">here</a>. It provides a better solution than the one offered below, so I recommend you check it out.</p>
<p>Although I love Flex, it can still be a bit buggy at times. I was working with an itemRenderer the other day and came across some very odd behavior. I had a list using an itemRenderer and when the data originally loaded everything was fine, but whenever I scrolled some of the data started disappearing. You can see this demonstrated in the sample below.</p>
<br/>
<div style="float:left">
<iframe src="/assets/pages/itemRenderer1.html" frameborder="0" width="310" height="230"></iframe>
</div>
<div style="margin-left: 315px;" class="code">
<code><span class='cc_normaltag'><mx:List dataProvider=<span class='cc_value'>"{myData.item}"</span><br /> variableRowHeight=<span class='cc_value'>"true"</span><br /> alternatingItemColors=<span class='cc_value'>"['#FFFFFF','#E6EEF3']"</span><br /> width=<span class='cc_value'>"100%"</span><br /> height=<span class='cc_value'>"100%"</span>></span><br /> <br /> <span class='cc_normaltag'><mx:itemRenderer></span><br /> <span class='cc_normaltag'><mx:Component></span><br /> <span class='cc_normaltag'><mx:VBox verticalGap=<span class='cc_value'>"0"</span>></span><br /> <span class='cc_normaltag'><mx:HBox></span><br /> <span class='cc_normaltag'><mx:Label text=<span class='cc_value'>"{data.Label}"</span> fontWeight=<span class='cc_value'>"bold"</span> /></span><br /> <span class='cc_normaltag'><mx:Label text=<span class='cc_value'>"{data.date}"</span> color=<span class='cc_value'>"#999999"</span> /></span><br /> <span class='cc_normaltag'></mx:HBox></span><br /> <span class='cc_normaltag'><mx:Text text=<span class='cc_value'>"{data.description}"</span> width=<span class='cc_value'>"100%"</span> /></span><br /> <span class='cc_normaltag'></mx:VBox></span><br /> <span class='cc_normaltag'></mx:Component></span><br /> <span class='cc_normaltag'></mx:itemRenderer></span><br /> <br /><span class='cc_normaltag'></mx:List></span></code>
</div>
<p>
Apparently, Flex likes to have all the items in a list the same height; so when an item such as the Text field in the example causes variation, Flex simply doesn't display it. I found that the easiest way to remedy the issue was to set explicit heights for the items in the renderer. Here is an example of how it works with the height explicitly set:</p>
<br/>
<div style="float:left">
<iframe src="/assets/pages/itemRenderer2.html" frameborder="0" width="310" height="230"></iframe>
</div>
<div style="margin-left: 315px;" class="code">
<code><span class='cc_normaltag'><mx:List dataProvider=<span class='cc_value'>"{myData.item}"</span><br /> variableRowHeight=<span class='cc_value'>"true"</span><br /> alternatingItemColors=<span class='cc_value'>"['#FFFFFF','#E6EEF3']"</span><br /> width=<span class='cc_value'>"100%"</span><br /> height=<span class='cc_value'>"100%"</span>></span><br /> <br /> <span class='cc_normaltag'><mx:itemRenderer></span><br /> <span class='cc_normaltag'><mx:Component></span><br /> <span class='cc_normaltag'><mx:VBox verticalGap=<span class='cc_value'>"0"</span>></span><br /> <span class='cc_normaltag'><mx:HBox></span><br /> <span class='cc_normaltag'><mx:Label text=<span class='cc_value'>"{data.Label}"</span> fontWeight=<span class='cc_value'>"bold"</span> /></span><br /> <span class='cc_normaltag'><mx:Label text=<span class='cc_value'>"{data.date}"</span> color=<span class='cc_value'>"#999999"</span> /></span><br /> <span class='cc_normaltag'></mx:HBox></span><br /> <span class='cc_normaltag'><mx:Text text=<span class='cc_value'>"{data.description}"</span> width=<span class='cc_value'>"100%"</span> height=<span class='cc_value'>"30"</span> /></span><br /> <span class='cc_normaltag'></mx:VBox></span><br /> <span class='cc_normaltag'></mx:Component></span><br /> <span class='cc_normaltag'></mx:itemRenderer></span><br /> <br /><span class='cc_normaltag'></mx:List></span></code>
</div>
<p>
Now, this isn't a perfect solution. What we are doing here is effectively the same thing as setting variableRowHeight to false; thus making all the items in the List the same height. So if anybody has a better solution for this issue please let me know.</p>
Simple string replacement with RegExp and Apexurn:uuid:0E10E563-3048-78A9-772E04391CC55D082008-10-08T12:10:00Z2008-10-21T08:10:00ZKalen Gibbons
<p>Sometimes it's hard to figure out even simple thing in a proprietary language like Apex. So here is a simple solution to a common problem.</p>
<p><strong>How do I replace string elements using Regular Expressions in Apex?</strong></p>
<p class="code">
<code>//create expression as Pattern<br />Pattern dollarPattern = Pattern.compile('[,$]');<br /><span class='cc_comment'><br />//replace all occurrences in a string</span><br />dollarPattern.matcher('$1,<span class='cc_numeric'>250</span>.25').replaceAll('')</code>
</p>
<p>You need to use Apex's Pattern class to create the regular expression. Then you can replace all matches in the string using the replaceAll() method.</p>
<p>This example takes a dollar formatted string ($1,250.25) and removes the dollar sign and comma to turn it into a number. The result would be 1250.25, perfect for database insertion or what have you.</p>
How to determine if a DataGrid or List has ScrollBarsurn:uuid:0E05349D-3048-78A9-7752FD024DC6FD3D2008-10-05T01:10:00Z2008-10-21T08:10:00ZKalen Gibbons
<p>There are occasions when you need to programmatically determine if a List or DataGrid has enough rows to require ScrollBars. If your DataGrid, for example, does not have an explicit rowCount or height specified, then it's not as easy as looking at its data provider.</p>
<p>The easiest way I've found it to use the "maxVerticalScrollPosition" property, which the <a href="http://livedocs.adobe.com/flex/3/langref/mx/core/ScrollControlBase.html#maxVerticalScrollPosition" target="_blank">Flex 3 Language Reference</a> describes as:
<br /><br /><span style="font-style: italic">"The maximum value for the verticalScrollPosition property. Note that this is not the height of the content because the maxVerticalScrollPosition property contains the height of the content minus the height of the displayable area."</span></p>
<p>
So if the the maxVerticalScrollPosition is greater than zero, then scrollbars must be available.</p>
<p class="code">
<code>if(myDataGrid.maxVerticalScrollPosition > 0){<br /><span class='cc_comment'> // is scrollable</span><br />}else{<br /><span class='cc_comment'> // not scrollable</span><br />}</code></p>
<p>
If anybody know of an easier or more efficient way of determine if a List has ScrollBars, please let me know.
</p>
BlogCFC: Extend the life of your blog postsurn:uuid:0E027514-3048-78A9-7715A060FE5C6B3D2008-07-12T07:07:00Z2008-10-21T08:10:00ZKalen Gibbons
<p>If your a BlogCFC user but don't post too often, like me, then you've probably seen the following message pop up on your blog:</p>
<div class="codeText">
Sorry There are no blog entries available.
</div>
<p>
By default, BlogCFC shows only entries posted within the last 30 days. If you'd like to extend this, simply locate the <span style="font-weight:bold; font-size:1.2em; font-style: italic;">tags</span> folder in your BlogCFC root and find <span style="font-weight:bold; font-size:1.2em; font-style: italic;">getmode.cfm</span>. Around line 68 you'll find the following declaration:
</p>
<p class="code">
<code>params.lastxdays = 30</code></p>
<p>
Simply change 30 to the number of days you'd like new entries to stay on the homepage and you're set, your blog will no longer look sad and abandoned.</p>
Yet another reason for disappearing background images in IE6urn:uuid:0DFC77C2-3048-78A9-77541EE74EAE34CF2008-06-10T08:06:00Z2008-10-21T08:10:00ZKalen Gibbons
<p>I was bit by another IE bug the other day; no matter how much I work with IE I never seem to be immune. That may be due to the fact that IE has sooo many problems. On this occasion several background images were disappearing in IE6. I tried the common solutions first: relative positioning, removing floats, setting widths, etc. and nothing worked. It took me quite a while to uncover the culprit.</p>
<p class="code">
<code>href=<span class='cc_value'>"javascript: void(<span class='cc_numeric'>0</span>);"</span><br /><span class='cc_comment'><br />//I was using it in a common manner:</span><br /><span class='cc_anchor'><a onclick=<span class='cc_value'>"switchTabs('comments')"</span> href=<span class='cc_value'>"javascript: void(<span class='cc_numeric'>0</span>);"</span>></span>Comments<span class='cc_anchor'></a></span></code>
</p>
<p>
Once I removed the <strong>href="javascript: void(0);"</strong> from the link everything worked fine. I had searched the Internet for days trying to find the solution to this bug and never found a thing. This is probably because not too many people use <strong>href="javascript: void(0);"</strong>... and now I know why.</p>
Verizon Wireless Media Storeurn:uuid:0DF9A1CE-3048-78A9-775AF47AA1970B522008-06-06T11:06:00Z2008-10-17T09:10:00ZKalen Gibbons
<p>The <a href="http://mediastore.verizonwireless.com/onlineContentStore/index.html" target="_blank">Verizon Wireless Media Store</a> is another pretty impressive website built with Flex. It's nice to see more and more large corporations adopting the technology. In my eyes, the less I have to deal with JavaScript, CSS, and browser incompatibilities, the better. Bravo Verizon.</p>