Archive

Posts Tagged ‘ActionScript’

Dedupe ArrayCollection Component

November 26th, 2008 Gareth 2 comments

Building off of my last post, I thought I might as well create a deduped arraycollection as well, just in case anyone wanted to use the data for something other than a combobox.  The implementation for this component is very similar to that of the combobox.  The DedupeArrayCollection allows you to pass it an array (one that has some kind of properties to each of the items within it), then set the dedupeProperty to whatever field you wish to dedupe.

The DedupeArrayCollection:

package com.archfamily {
 
	import flash.events.Event;
	import flash.utils.Dictionary;
 
	import mx.collections.ArrayCollection;
	import mx.events.CollectionEvent;
 
	public class DedupeArrayCollection extends ArrayCollection {
 
		private var _dedupeProperty:String = "";
 
		public function set dedupeProperty( value:String ):void {
			_dedupeProperty = value;
			this.source = this.source;
		}
		public function get dedupeProperty():String {
			return _dedupeProperty;
		}
 
		/**
		 * 
		 * Needed to override the standard dataprovider in order to reset
		 * the duplicate value each time
		 * 
		 */
		override public function set source( value:Array ):void {
			var _returnArray:Array = value;
 
			if ( value && dedupeProperty.length > 0 ) {
				var _map:Dictionary = new Dictionary( true );
 
				value.forEach( function( item:*, index:int, array:Array ):void {
					_map[ item[ this ] ] = item; // in the loop, this == dedupeProperty
				}, dedupeProperty );
 
				_returnArray = [];
				for each ( var object:Object in _map ) {
					_returnArray.push( object );
				}
			}
 
			super.source = _returnArray;
		}
 
		public function DedupeArrayCollection( source:Array=null ) {
			super( source );
		}
 
	}
}

The implementation of the arraycollection:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()" xmlns:archfamily="com.archfamily.*">
	<mx:Script>
		<![CDATA[
			import com.archfamily.DedupeArrayCollection;
 
			[Bindable] private var ac:DedupeArrayCollection = new DedupeArrayCollection( [ { name: "car", total: 100 },{ name: "bus", total: 200 },{ name: "bike", total: 300 },{ name: "train", total: 200 },{ name: "boat", total: 400 },{ name: "car", total: 500 },{ name: "bus", total: 200 },{ name: "convertible", total: 100 },{ name: "gizmo", total: 300 },{ name: "boat", total: 300 },{ name: "car", total: 100 },{ name: "dune buggy", total:300 },{ name: "motorcycle", total: 100 }] );
 
			public function init():void {
				ac.dedupeProperty = "total";
			}			
		]]>
	</mx:Script>
	<mx:VBox>
		<mx:ComboBox id="testing" dataProvider="{ ac }" labelField="name" />
	</mx:VBox>
</mx:Application>

The only thing I would probably change is to figure out what event needs to fire when my dedupeProperty is set to get the arraycollection to reload the source. Currently I’m just setting the source to itself so that the event fires and reloads the arraycollection, but just firing the event would probably be less overhead.

Deduped ComboBox Component

November 26th, 2008 Gareth 1 comment

There are times that I have wanted to remove all duplicates from a combobox’s dataprovider, but haven’t wanted to requery the database or roll my own code snippet each time to remove those duplicates.  To make my life a little easier (and hopefully anyone else that may be in need of this feature), I’ve created the DedupeComboBox class.

This handy little item allows you to set the dataprovider of the combobox to an array or arraycollection, and set the labelField value and the combobox will then handle the rest.  The labelfield is important as that is what allows the component to remove the duplicates from the arraycollection (if it is an array, it must also be an array of objects with properties that match the labelField or it will not remove anything). Also, as the items populate the deduped dictionary instance, the value of that item in the arraycollection is saved to that “key” in the dictionary, allowing for retrieval of it later on if necessary.

package com.archfamily {
 
	import flash.utils.Dictionary;
 
	import mx.collections.ArrayCollection;
	import mx.controls.ComboBox;
 
	public class DedupeComboBox extends ComboBox {
 
		/**
		 * 
		 * Needed to override the standard dataprovider in order to reset
		 * the duplicate value each time
		 * 
		 */
		override public function set dataProvider( value:Object ):void {
 
			var _localArray:Array = ( value is ArrayCollection ) ? ( value as ArrayCollection ).source : value as Array;
			var _map:Dictionary = new Dictionary( true );
 
			if ( labelField.length > 0 ) {
				_localArray.forEach( function( item:*, index:int, array:Array ):void {
					_map[ item[ this ] ] = item; // in the loop, this == labelField
				}, labelField );
			}
 
			var _returnArray:Array = [];
			for each ( var object:Object in _map ) {
				_returnArray.push( object );
			}
 
			super.dataProvider = _returnArray;
		}
 
		public function DedupeComboBox() {
			super();
		}
 
	}
}

then to implement it from your code you could do something as simple as this

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:archfamily="com.archfamily.*">
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			[Bindable] private var ac:ArrayCollection = new ArrayCollection([ { name: "car", total: 100 },{ name: "bus", total: 200 },{ name: "bike", total: 300 },{ name: "train", total: 200 },{ name: "boat", total: 400 },{ name: "car", total: 500 },{ name: "bus", total: 200 },{ name: "convertible", total: 100 },{ name: "gizmo", total: 300 },{ name: "boat", total: 300 },{ name: "car", total: 100 },{ name: "dune buggy", total:300 },{ name: "motorcycle", total: 100 }]);
		]]>
	</mx:Script>
 
	<archfamily:DedupeComboBox id="testing" dataProvider="{ ac }" labelField="name" />
</mx:Application>

You can even get just the non-duplicate totals by changing labelField=”name” to labelField=”total”.

Returning typed objects to Flex from ColdFusion

April 14th, 2008 Gareth No comments

Back in January I saw Brian Kotek’s post about returning typed structs to Flex. When I first read this article, I wasn’t sure how useful it was (I guess I was getting a little confused with the addition of Transfer and AOP in the article, and figured it was just something for that framework). A few weeks later I came across another article about the same idea, and something clicked and I realized just how brilliant this was.

Previously in order to return a typed object to Flex from Coldfusion, you would usually set up aliasing within both your ActionScript object and your CFC

AS:

[RemoteClass(alias="com.mySite.UserVO")]
public class UserVO {

CFC:

<cfcomponent alias="com.mySite.UserVO">

Then, when you transfer objects back and forth between ActionScript and ColdFusion, they are automagically converted to that specific type (along with all of the methods that go along with them). The only bad thing with this method, is that in order to transfer the CFC VO back from ColdFusion to ActionScript, you have to create that object in ColdFusion. Now this doesn’t create much overhead for one object, but if you query the database and return those query rows as separate objects, you have to createObject on each query row, which is an insane hog of memory and server resources. Plus, ActionScript cannot use any of the extra methods that CF is returning, so really anything other than the CFC object’s properties are just extraneous information.

Using the newly discovered technique, you can return the CFC object’s properties as structs rather than having to use createobject each time. You create the properties of the CFC as keys in the struct, such as

myStruct['firstName'] = "John";
mystruct['lastName'] = "Doe";

All that’s needed is to set one extra key in the struct e.g. myStruct['__type__'] = “com.mySite.UserVO” When the items are returned to ActionScript any struct that has __type__ as a key is automagically converted to an object of that type. What’s even more brilliant is if any items within the struct also have an __type__ (e.g. if the user has a company, and that company is returned as a company struct using the same __type__ methodology) then they also get converted to that typed object, so some sort of recursion is happening also.

Now for the sad news (on my part at least). After spending 3 days trying to get this to work on CFMX7 (I had read in a couple of different places that this supposedly would work in CFMX7), I finally found that it apparently only works via LiveCycle or CF8 (which has Flex Data Services Express, I think). After trying everything imaginable, I ended up just having to write a function to convert the returned data to objects. Now I’m hoping that my company will upgrade to CF8, but I don’t think that will be happening. It looks more likely to be Java + WebORB. I’m not sure if this same capability is possible with WebORB, but I’m hoping it does. Certainly is a nice feature to have. Anyway, hopefully this post will be informative for those with CF8 (or LiveCycle) and save those others with CFMX7 from going down the same path as me for 3 days :)

The original post with a little more details is on the CFTalk Mailing List