Zend AMF and Flash Builder

While I was pondering creating the Flex/Flash test application for the Demo site, I ran across Flex Test Drive.  I remember reading it before and couldn’t remember why I didn’t go through with the example….then I tried connecting to the php web service.  The Flex Test Drive gives you three options for a server:  Java, PHP and ColdFusion.  I don’t have a ColdFusion or Java option on my hosted website, so PHP was the way to go.  I also didn’t want to bother installing a web server locally, because I want to post my examples on my site.  Because of this, installation is probably not as straight forward as I hoped it would be.

The first part of Flex Test Drive creates the starting application, which you choose the server backend.  Since I wanted to use my website as the server, I put in http://demo.deanlogic.com for the Root URL.  The example points to a local web server, so this is where I started to diverge from the game plan.  The next part was to create a database using MySQL server and then add some basic components to the application.  All of that went fine, after a few short hick-ups in the sql statement to populate the tables.  The next step is connecting to the database using the PHP remote connection and that’s where I got into trouble.

The PHP remote connection uses Zend AMF, which is part of the Zend Framework. Apparently in Flash Builder 4.5, the integration is even closer.  However, part of the setup of the PHP Zend AMF connection adds the Zend Framework to the application directory.  Once that is added, you have to updated the amf_config.ini file to point to the framework and library directories.  This is were it got a little confusing for me.  Since the initial directories are locally on my PC, I didn’t know which directories to use; UNIX or Windows.


[zend]
;set the absolute location path of webroot directory, example:
;Windows: C:\apache\www
;MAC/UNIX: /user/apache/www
webroot = /home/users/web/deanlogiccom

;set the absolute location path of zend installation directory, example:
;Windows: C:\apache\PHPFrameworks\ZendFramework\library
;MAC/UNIX: /user/apache/PHPFrameworks/ZendFramework/library
zend_path = ZendAMF/Zend/ZendFramework/library

[zendamf]
amf.production = false
amf.directories[]=services

My first attempt was to use the UNIX directories, but it would end up with not being able to find the include files.  I even downloaded the ZendFramework from the Zend site and loaded it up to my site.  Nothing seem to work.  I even tried altering the gateway.php file to point directly to the directories without using the check code included.  Going directly to the gateway.php on my website would show the same error I was getting when connecting.  So, I figured I could modify the init file until that error went away.  After several attempts at different directory options, I finally saw “Zend Amf Endpoint” on the gateway page.  Woo hoo!!

Unfortunately the PHP remote connection still wasn’t working, which is when I noticed that it said something about the release folder and the gateway file.  When I initially deployed the Flex application, it was under the bin-debug folder, while the ZendFramework was a few levels higher.

By moving all of the deploy files to the same level as the ZendFramework folder, I finally got the PHP Zend remote connection to work.  When the connection works, it uses the EmployeeService to get information from the database to be used in the rest of the Test Drive demonstration.

Hopefully later I get the directory setup so it is a little cleaner.  It seems that everything I add just drops into the main folder.  The Dreamweaver Widgets did this as did the CSS from the style sheet.  I prefer things to be much more organized.  But, for now, I’m glad the data connection is working so I can move on with the Test Drive.

 

ArrayCollection in an ArrayCollection

At work I am trying to display a bunch of information retrieved from a web services.  The data has a header table (top item) and then supporting item tables (sub items).  My current data only brings back one top item, but I have set it up to display multiple top items using a HorizontalList.  I created a custom component based on a Form, which allows me to easily display header and values.  In the future, I can probably use the form for inputs, but for now it is just displaying.  I am also using an Accordion container to display each of the header items that are wrapped in an overall item.  In each Accordion item, I dynamically create a box, to hold the form, which is dynamically created by passing it in as a new ClassFactory.  The Form acts as an item render in the HorizontalList.  Well, the problem I ran into is, that you can only pass in one DataProvider into the HorizontalList.  This was causing an issue with an item that would have an over all header information and then a DataGrid full up sub items.   After starting to fuss around with other options, it occurred to me to pass in the sub items as an ArrayCollection type.

For example, if I had a class called MyObject


package {

public class MyObject {

[Bindable]
 public var ID:Number:

[Bindable]
 public var Name:String:

[Bindable]
 public var itemList:ArrayCollection
}
}

And earlier I populated an ArrayCollection called itemListArrayCollection with data, then I wanted to add this to an ArrayCollection called myMainArrayCollection, it would look something like this.


var newObject:MyObject = new MyObject();

newObject.ID = 1;

newObject.Name = 'Test';

newObject.itemList = itemListArrayCollection;

myMainArrayCollection.addItem(newObject);

Then, in the Form I created to display the items, I would set the FormItems to show ID and Name


<mx:FormItem>

<mx:Label text="{data.ID}" />

</mx:FormItem>

<mx:FormItem>

<mx:Label text="{data.Name}" />

</mx:FormItem>

And the DataGrid within the form would get it’s DataProvider through the initial data value.  I can also point to the columns (DataFields) in the itemListArrayCollection in order to set up the DataGridColumns.


<mx:DataGrid dataprovider="{data.itemList}">

<mx:columns>

<mx:DataGridColumn DataField="listField1" />

<mx:DataGridColumn DataField="listField2" />

<mx:DataGridColumn DataField="listField2" />

</mx:columns>

</mx:DataGrid>

I’m sure I’m not the first person to pass an ArrayCollection inside of an ArrayCollection, but it was an “ah ha!” moment for me today.  I’m not sure if it is considered best practice to do this, but it works for what I need much simpler than trying to create a component to receive multiple multiples of DataProviders.  Once I get things straightened out with the current web services, I know I will have to go back and probably have an overall ArrayCollection with 3 – 5 ArrayCollections passed into it.

Adobe BrowserLab

I decided to take a glance at the widgets I put in earlier today and stumbled onto a nice little tool over at Adobe.  In Dreamweaver you have a few options for viewing your work to determine how it will look in the real world.  The first method is to use a split view, which gives you one frame of code and another frame of design.  The obvious benefit is that you can quickly find your code problems before sending it up to the site.  However, as you notice from the image below, it might not actually be what  you really see.

Adobe apparently has their previewer using some of the same code as Chrome, because the color changes I added to the Aqua Button widget show in the preview but not in my FireFox browser.  Dreamweaver helps you determine what the page will look like in the real world, without loading every version of every browser, with a Preview Menu.  On the menu are the browsers loaded on your PC and then a couple of other options.

There is a Preview in BrowserLab option that launches Adobe BrowserLab.  This, complimentary until April 12, 2012, tool allows you to view a web page in multiple browser simulators.  The browser choices even differentiate between OS version, because there are FireFox for OS X and Windows options.  The menu launches BrowserLab with your file version of your page or  you can load your site using the URL.   You can select multiple browsers for viewing the site, but BrowserLab will do a initial loading of all the select browsers before you can view.  Once everything is loaded, you can switch between the browsers selected and view 2 browser options at the same time, either in split view or onion layers. From the screen shot below, you can see that Chrome displays orange buttons, while FireFox does not.  This makes BrowserLab a very useful tool for quickly viewing your website across many browser version.  I hope that Adobe keeps it free for those who have Dreamweaver.  I also have used Adobe Story for some movie projects, which also has a “complimentary until April 12, 2012″.  I am guessing Super Duber Master Creative Collection Suite 6 will be launched then.  Maybe by then, I’ll have made some money off of one of my hobbies to pay for the expensive upgrade.

The other option on the Preview menu is Preview in Device Central .  Device Central is part of a few different Adobe applications.  It makes sense that Dreamweaver would give a device preview.  Everybody wants to know how their site will look like on mobile devices or a tablet or even a television. Yes, a television.   There is a device library that allows for downloading of different device profiles.  Even though Apple doesn’t like Adobe much, apparently Adobe is nice enough to provide iPad and iPhone profiles.  There are also BlackBerry phone and tablet profiles and bunch others.  And if Adobe didn’t create a profile you are looking for, apparently you can create one and share it in the library.  Once you have download the profile, you can add it to your test devices.

Finally, you can use the Multiscreen Preview to see how your site will look in different screen resolutions.  The default sizes are Phone (320 x 300), Tablet (768 x 300) and Desktop (1126 x 276).  Since these dimensions won’t fit all issue, you can modify the sizes, however, they might not fit neatly in the three pain window like the defaults.  You can also use this tool to setup multiple css files to be shown based on the size of the screen (small, medium, large).

With all of these tools, it will be easy for anyone to prepare their site for almost any possible viewer.

Dreamweaver Widgets

Dreamweaver has a Widget Browser for checking out the free and paid Dreamweaver widgets in the Adobe Exchange.  The benefit of the Widget Browser is that you can easily see which ones you have installed and what is available without having to go to the website.

When you decide on using one, then you can use the Widget Browser to configure the widget, so some success.  It all depends on the developer as to how useful the widget configuration is and customizing your selected widget.  I downloaded and installed the Aqua Button, the Weather Updater and the Twitter widgets.

The Weather widget has the configuration screen so that you can see what was setup, but you can’t edit the cities displayed in the widget and set it as a personal preset.  But, since I could see the code behind, I did a quick search (weather ‘INXX0012′) and figured out it was using city codes from Weather.com.  Once on the site, I looked up some cities and took the code from the URL.  Then I put the city codes into the function call that places the widget on the page.  The style sheet for the widget didn’t display the full widget, so I had to adjust the height slightly in order to see the “Read full forecast” text at the bottom of the widget.

The Aqua Button widget configuration has a lot more options, which allow you to change size, color, font and even add the text.  However, after saving the settings and attempting to insert it into page, the settings didn’t really change anything on the buttons.  As stated before, it possible that the developer of the widget didn’t do something right and that is the reason that the changes I made to my preset didn’t appear on the web page.  Which brings me to the Twitter Client.  UPDATE : The preset options do show up in Chrome.

The Twitter Client confirmation screen has plenty of options for changing the color, font styles and even pointing to a Twitter account.  However, it only shows either tweets from, to , mentioning or tagged, but not all (at least from what I see).  I made a personal configuration, saved it and then inserted into the Demo site page.  The changes I made in the configuration showed on the page, just as it looked in the preview for the configuration.  The only small issue deals with the how the preview looks and how it actually works in the site.  If I decided before hand on the width of the all the widgets, then I could have easily entered in that value.  But, since I am just throwing things on the Demo page and seeing what would stick, I decided to change my preset and then re-insert it into the web page.  It would be nice if there was a link between updating the preset and having it change in the Dreamweaver site.  Because it isn’t very hard to delete the widget code, you can select the main tag and collapse the code, it isn’t a huge issue.  Also, I could have still just updated the inserted code to include the changes I made to the widget.

After I inserted the Twitter Client, the Weather Update client stopped working.  Not a very good sign.  Hopefully it means the Weather.com site is down.  If it doesn’t come back, I guess I’ll have modify the widget to get it to work again.

Adobe Edge and HTML5

Last night I downloaded Adobe Edge, which is Adobe’s tool for creating HTML5 basic animations.

Adobe® Edge is a new web motion and interaction design tool that allows designers to bring animated content to websites, using web standards like HTML5, JavaScript, and CSS3.

Edge will be updated regularly to add new functionality, stay ahead of evolving web standards, and incorporate user feedback to provide the best functionality and experience possible. This is an early look at Edge with more capabilities to come.

The current capabilities are very limited.  You can added Text and boxes to a canvas, plus you can import images.  There is a timeline, similar to what is seen in Adobe Premiere and I guess now Adobe Flash.  I haven’t looked into Adobe Flash very much, but I have been using Premiere for my movie projects. In the timeline, you add key points and then you can alter the color, scale, skew, position, opacity and rotation. It is fairly simple to use.  When you click on the object you have added and make a change using the properties panel, it automatically enters a layer for the effect.  I added the effect I created to the Demo site, but it only ran once.  The “Preview in Browser” works fine, but copying the JavaScript links and files, plus adding the div tag seems to not work entirely.  I probably broke it when I added my site logo to the animation. Anyway, I’m not that overly impressed.  I see articles that HTML5 will be the end of Flash.  Apparently these authors know nothing of Flex and that’s probably Adobe’s fault for melding the names together.  Yes, Flash is a timeline based animation tool, but it does a little more than that.  Flex is an application tool that outputs to Flash.  I’m not sure if Flex can be displayed using HTML5.  Just like Java, CGI and Perl haven’t gone away, I don’t see Flash going away, even if a certain fruit company has a problem with it.

Regardless of my first attempts with Edge Beta 2, I will be trying to add HTML5 elements tot he Demo site, because it is the latest buzz word and well, I’ll let Larry Ellison explain it.

SAP web services and Flex

The company I work for uses SAP for their CRM (Customer Relations Management) solution.  We were on Oracle, but after being bought out by ze Germans, we had to switch to SAP.  The idea was to integrate the German offices with the American offices. That never happened and we ended up splitting off from the Germans this year.  However, SAP is still with us.  My boss requested that I create some sort of application to check if the web services called by our mobile CRM application, Service Data Automation (SDA), (created by me) were working as part of an overall systems check method.  The logical answer is, if the requests aren’t going through, then there is something wrong with the web services.  But, regardless of the obvious, it would be a good opportunity to show what Flex can do.  And if I can get the connections setup in Flex, then it would be a step closer to building a BlackBerry PlayBook or QNX enabled handheld device option using Flex.

The web services called by the SDA application actually use a middle-tier .Net platform (which I didn’t create) .  Since those that did create it and maintain it are no longer with the company, I have to figure out what each of the web services are doing.  I had created a Flex application earlier that connected to the SAP web services, but it is different than the web services used by SDA.  Luckily, I wasn’t the only one to go down this road.  At Computers Should Be Less Friendly, the author gives a quick an dirty example on how to connect to a SAP web service.  The only thing is doesn’t cover is the certification of the user.  For SDA, we created a generic user whose password never expires in order to process web services calls.  The web services still check to see if the person making the call is a valid user, so we have to pass in that identification as well.  But, by having this user, we only need one log-in and it won’t expire every 30 days (ugggh!!).

The normal connection string contains the username and password.  Usually I would store the user and password in order to switch the values when pointing to different instances.  It would look something like this.


http://crmurl.de:8033/sap/bc/srt/rfc/sap/ZCRM_DATA_WS?sap-client=sapClient&wsdl=1.0&style=rpc_enc&amp;sap-user=" + sapUser + "&amp;sap-password=" + sapPassword;

To add the user, password and client information, you need to add header information to the web service.


var sapWS:WebService = new WebService();

sapWS.headers["Authorization"] = "Basic " + encoder.toString();
sapWS.headers[ "sap-user" ] = sapUser;
sapWS.headers[ "sap-password" ] = sapPassword;
sapWS.headers[ "sap-client" ] = sapClient;

For my web services check, I made the web service dynamic by using a switch to determine the end point and uri of the web service.  On the display, I setup a ViewStack that contained a form for entering in parameters and a button to kick off the web service.  The button pointed to the function that built the web service and provides the case value.


switch (wsCheckName) {
case "PartLookup":
sapWS.wsdl = serverStartURL + partsLookup_WSDL + serverEndURL;
sapWS.addEventListener(LoadEvent.LOAD, partsLookup_load);
sapWS.addEventListener(ResultEvent.RESULT, partsLookup_results);
break;
case "InventoryLookup":
sapWS.wsdl = serverStartURL + inventoryLookup_WSDL + serverEndURL;
sapWS.addEventListener(LoadEvent.LOAD, inventoryLookup_load);
sapWS.addEventListener(ResultEvent.RESULT, inventoryLookup_results);
break;

}

The one thing to keep an eye out for is to verify if the web service is the same as the end point.  I believe that normally, this would be the case.  However, the person who created our custom web services in SAP apparently didn’t keep the naming convention the same.  So, I couldn’t pass the WSDL parameter (i.e. inventoryLookup_WSDL = Z_CRM_SDA_MAT_INV) in as the Operation call, because it was different.


<wsdl:portType name="Z_CRM_SDA_MAT_INV"><wsdl:operation name="Z_CRM_SDA_MAT_INV_DISPLAY"><wsdl:input message="tns:Z_CRM_SDA_MAT_INV_DISPLAY"/><wsdl:output message="tns:Z_CRM_SDA_MAT_INV_DISPLAYResponse"/></wsdl:operation></wsdl:portType>

Luckily, it is just a matter of pulling up the WSDL and finding the operation name and using that in the LoadEvent function.


var op:AbstractOperation = sapWS.getOperation(inventoryLookup_op);

var bapiInput:Object = new Object();
bapiInput.INVENTORY_DATA = new Array();;

bapiInput.R3RFCNAME = new Array();
bapiInput.R3RFCNAME.push(R3Destination);
bapiInput.LOCATION_DATA = new Array();
var locationRow:Object = new Object();
locationRow.WERKS = inventoryForm.ilWharehouse.text;
locationRow.LGORT = inventoryForm.ilBin.text;
locationRow.ALWAYS_SEND = "1"
bapiInput.LOCATION_DATA.push(locationRow);

bapiInput.MESG_T = new Array();
bapiInput.MESG_T.push();
bapiInput.MATNR = new Array();
bapiInput.MATNR.push(inventoryForm.ilPartNumber.text);
bapiInput.QUANTITY = new Array();
bapiInput.QUANTITY.push("1");

The biggest problem right now is building the tables and passing in the correct values to the proper columns.  WERKS?  What the heck is that?  I think it’s the Wharehouse and LGORT is the Location.

UPDATE

It seems that the header credentials never really worked.  The only thing that seems to work is putting the sap-user, sap-password and sap_client onto the end of the WSDL URL.  And, after figuring out that worked for the first part of the web service call, I tweaked and tested and tweaked and test until I cam across the obvious (not so to me at the start) solution that those values are also required in the endPoint URI.  Before, I kept the WSDL and endPoint URL/URI separate thinking that the extra information wasn’t need in the endPoint.  Well, it is now obvious to me that it is needed.  So, forget the headers part, it doesn’t seem to work, but the URL values works like a charm.

For each case, I added a second line to set the endpointURI.  It is exactly the same as the wsdl.  I also added the encodeURI function as well.


sapWS.wsdl = encodeURI(serverStartURL + partsLookup_WSDL + serverEndURL);
sapWS.endpointURI = encodeURI(serverStartURL + partsLookup_WSDL + serverEndURL);

For the serverEndURL, I make sure I have the sap-user, sap-client and sap-password.  I created a couple of new parameters to hold the current password and client based on which instance I want the application to point to (Dev or Test).


serverEndURL = "?wsdl=1.1&style=rpc_enc"
+ "&sap-user=" + sapUser
+ "&sap-password=" + currentPassword
+ "&sap-client=" + currentClient;

The Demo Site

I have created a Demo site using Dreamweaver.  I used a HTML5 template, because I figure I probably should learn some HTML5 while I am doing this.

The first thing I had to do was setup a ftp user on my website and give the user access to the “demo” folder.  To make things simple, I also created a subdomain for the demo folder (http://demo.deanlogic.com).  Unfortunately, the Dreamweaver template is a little finicky and the path url to the image wasn’t correct on my first couple of attempts to drag and drop the image into the page.  Also, the css added to the page when using a pre-defined template causes hickups when you delete code.

For now, I have just removed the default text on how to use the template and added my site’s logo. Baby steps.  Because I created the index page as a php type, I can add a little php code to the page as part of the example.  A quick demo would be to add the copyright notice in the footer.

As most coding sites do, php offers examples at the bottom of the functions page.  This is very helpful if you don’t fully understand the function.

To create a copyright notice that continues to update without intervention, you only need to get the current year and display it after the copyright text and symbol.

Copyright &copy; <?php echo date('Y'); ?>

So that it is a little more “authentic”, the copyright year should probably be in the format of a range (i.e. 2007-2010).  This way, you can have a static start year and a continuing end range.  Since the start for the Demo site is this year, then I will be a little more tricky and only do the range once the year flips over to 2012.

Copyright &copy; 2011
<?php
if(date('Y') != 2011) {
print(' - ' . date('Y'));
}
?>

Actually, not very hard or tricky to do.  Just check to see if the current year isn’t equal to the set year (i.e. 2011) and if it isn’t, then print out the dash and the current year.  The start year is static.

I’ll probably add some more simple php script to the main demo page later.  I know I will probably have to use some other php script for other examples in the future.

Time for some practice

While I was at work pondering what other better careers there might be out there, I decided that I probably should make sure my skills are up-to-date.  Since I am limited to what software I have installed on my home PC, I will be brushing up on those skills and learn some new ones in the process.  The best way for me to learn something is to actually have something to do, instead of just reading through a book and trying to absorb it.  I’ve absorbed plenty of useless facts by reading, but that doesn’t beat actually putting to work knowledge that has been gained.

I plan on going through the Flex/Flash Builder and attempt to use as many features as possible.  In order to do this, I’ll need to have something things setup to show what I create in action.  Beyond having a website available to do this, the first step is to setup a empty database and tables on the site, so I can input data and retrieve data.  I’ll use Google Docs – Drawing to map out the basic database and post it below.  It’s not exactly a database mapper, but it is free and pretty simple to use.  I’ve embedded the published page, so if I make updates, it should update what is seen below.

To keep things simple, I’ll just create a 3 table database for now.  A Customer, Address and Contacts table.  By not including the address or any contact information in the Customer table, I can create multiple contacts types and addresses for each customer.  For example, if the customer has an e-mail, main phone and cell phone as methods of contacting, then I would have 3 entries in the Contact table for the one customer.  Later, I should add a boolean value to determine which of the Contacts is the primary and make sure the method of input verifies only one Contact is selected.  Like wise for the Address.  The address could be the physical, delivery, billing or another type of address.  If it is the physical address, I will probably want to add Latitude and Longitude information, in order to connect any map tools.  And, I will need to added a primary flag as well.  I added a Nickname field in order to give the location a name relative to it’s purpose.  An example of this is a customer with multiple satellite locations.  You still have the one customer, but there are multiple physical addresses.  Most likely, in real world situations, the customer would have multiple customer accounts for each of the physical locations.  I’m sure a debate would be endless on the merits of both.

Another thing to consider is the Type values.  Some would probably argue that the proper way to handle the types is to create a table for the Types and use the ID in the Customer, Contact and Address tables.  Of course, this would also require setting up a table to determine which types would go into the corresponding list value.  This is why you map out your database before you start creating it.  Which I didn’t, but since I don’t have any data in my database, I can easily change the column types.  I could have made it even more lose on the tables and called the Customer table something like Human and allowed it to be any type of Human that will be using the application, but I think that is fine.  The only issue is, that the Address and Contact tables are actually just Customer Address and Customer Contact.

I am using MySQL 5 for my database, because that’s what comes with my website.  The site also uses Perl 5 and PHP 5, so I will be using PHP for any back end scripting that I need.  Since I have Dreamweaver installed, I plan on creating a demo site using that, instead of just adding pages inside of my WordPress blog.  This will also give my wife the opportunity to see how Dreamweaver works.  I would like to figure out some skinning for Flex, so I will use Fireworks and possibly Flash Professional for that.

Now that I have my basic database setup, it is time to figure out how I am going to go about down this learning/refreshing path.

Google Docs in Flex frustration

I enjoy using Google Docs.  I have to admit, it is a very easy way to share information between people and to do on-line collaboration.  I have used documents to brainstorm ideas and create outlines in real time on-line.  Recently I created a form that stores the information submitted into a spreadsheet.  Unfortunately,  the spreadsheet is a little hard to read with the responses are very long and there are multiple long responses.  The provided “summary” view for the spreadsheet doesn’t help, because it just displays all the answers together.  This would be great for a survey, but not for a questionnaire.  I decided to see if there was a way to get the spreadsheet data and display in a better format, preferably a Flex/Flash application that could be put into a blog page.

The Spreadsheet API provides the information for retrieving and even updating a Google Spreadsheet.  I first attempted to download the spreadsheet in CSV format, but that didn’t work.  The CSV URL returned a streaming error that might be due to me not setting up the call correctly or a restriction by the Spreadsheet application preventing the Flex/Flash access.  After hunting around for a little bit, I found AuthSub in ActionScript .  This is one of Google’s methods of authentication.  After a quick attempt to get it working, I did a search and found that this probably wouldn’t satisfy my needs either.  Since it uses authentication, it will mean that each person who logs on to the site will have to authenticate through Google.

I tried using the “public” view feature on the spreadsheet, but the error back stated that the spreadsheet didn’t exist.  In multiple attempts at different URL formations, nothing worked.  Most likely, I’ll have to setup something in PHP to retrieve the spreadsheet, store it, then access the data.  I’ll have to take a look at it sometime later.

 

UPDATE

Well, apparently it is much easier to view the public spreadsheet, if the spreadsheet if set to “Public” and not “Private”.   Welp, onward and upward!

ArrayCollection column counts

As part of an example of trying to read data from SharePoint and display it in a Flex/Flash application, I needed to see if I could create pie charts from the data.  After figuring out how to get the list data as an xml output, then cleaning up the data to insert it into a ArrayCollection, the next step was to count the number of times a particular value was used in a particular column.  If I was using SQL, it would be  a straight forward grouping and count.  The work around was to filter out the unique values and then filter the ArrayCollection on that value getting the count.

Finding the unique values was simple, because I knew someone had already created the query example for doing so.  It was just a matter of searching the web and finding the code.


//takes an AC and the filters out all duplicate entries
public static function getUniqueValues (collection:ArrayCollection, propertyName:String):ArrayCollection {
var length:Number = collection.length;
var dict:Dictionary = new Dictionary();

//this should be whatever type of object you have inside your AC
var obj:Object;
for(var i:int = 0; i < length; i++){
obj = collection.getItemAt(i);

dict[obj[propertyName]] = obj[propertyName];
}

//this bit goes through the dictionary and puts data into a new AC
var unique:ArrayCollection = new ArrayCollection();
for(var propertyString:String in dict){
unique.addItem(dict[propertyString]);
}
return unique;
}

With the unique values being returned, then I just needed to loop through each value to do a filter on the original ArrayCollection to get the count. There were several examples that I found, but they didn’t work, because they didn’t completely do what I needed.  Part of the script had to include the filter function within the overall function.  By creating the filter function as a variable, the loop call could use the filter for each filter by value.  Since I planned adding an object to the final array of name and value, I used the name part of the array to hold the filter value.  Then when the count was returned, but putting the array in to a temporary array and getting the length, I added the count to the object.  The final code looks extremely simple.


//Takes an AC of values and finds the number of matching values in another AC to return a count
public static function getValueCounts(sourceCollection:ArrayCollection, valueCollection:ArrayCollection, propertyName:String):ArrayCollection {
var length:Number = valueCollection.length;
var countArray:ArrayCollection =  new ArrayCollection();

var filterFunction:Function = function(element:*, index:int, arr:Array):Boolean {
return element[propertyName] == this.name;
}

var thisValue:String;
var countObject:Object;

for(var i:int = 0; i < length; i++){
countObject = new Object();
countObject.name = valueCollection.getItemAt(i);
var tmpCollection:Array = sourceCollection.source.filter(filterFunction, countObject);
sourceCollection.refresh();

countObject.value = tmpCollection.length;
countArray.addItem(countObject);
}

return countArray;
}

To use this, I simply create a FilterBy array from the original using the column I want to find unique values in, then pass the original, the unique values and the column to the function to get the name/value count array.


FilterValuesArray = getUniqueValues(SourceArrayCollection, "ColumnToFilter");
ValuesCountArray = getValueCounts(SourceArrayCollection, FilterValuesArray , "ColumnToFilter");

I used the final count array to display a pie chart.