Home Projects Flash CS3 How to Create a Flash Searchable DataGrid in AS3 using XML from MS Access





Forgot your password?
Forgot your username?
No Account Yet? Create an account

Like it? Share it!

Add to: JBookmarks Add to: Facebook Add to: Windows Live Add to: Ximmy Add to: Digg Add to: Del.icoi.us Add to: Reddit Add to: Jumptags Add to: Upchuckr Add to: StumbleUpon Add to: Slashdot Add to: Netscape Add to: Yahoo Add to: Blogmarks Add to: Diigo Add to: Technorati Information

How to Create a Flash Searchable DataGrid in AS3 using XML from MS Access PDF Print E-mail
User Rating: / 16
PoorBest 
Projects - Flash CS3
Written by drooza   
Tuesday, 07 October 2008 22:47
Article Index
How to Create a Flash Searchable DataGrid in AS3 using XML from MS Access
The ActionScript
Making the DataGrid
Loading the XML
The Exported XML File
Creating Inputs, Lists, and Labels
Array Filters (for DataProviders)
View the Example
All Pages

Here's one more for XML integration, but this time using more components offered in Flash CS3.  This article will focus on the how easy Flash components integrate with XML.  This way uses ActionScript 3.0 and not a XML data connector. This way is for implementing a need for searchable items where internet access is not desired or implied.

 


First we should plan out how this will integrate.

access to xml to swf

Why MSAccess? Why not some other relational database management system (RDBMS) such as MySQL? 

  • Usability:  It's easy for the client to keep track of information in a database tool they're familiar with.  In this case, it's Microsoft Access.
  • Domain:  This application is for use on a distrubuted CD/DVD that will enable the user to search through data efficiently.  Since most RDBMS require a server and/or internet access, this pseudo-database will just run from flash and filter an XML file.

Since MSAccess can export external data as XML, ActionScript can read that file and place it in the datagrid. 

Sorry, if you're reading this article thinking, "How can flash read a MS Access database?"  I have one answer. Maybe VB is your answer or maybe even Silverlight.  Flash does not read MSAccess databases unless there exists some JDBC/ODBC driver to read.  But why do that when MS Access exports XML that flash can read?  Anyways, on to the application!

 



 The ActionScript - import statements...

 import fl.controls.CheckBox;
import fl.controls.DataGrid;
import fl.controls.Label;
import fl.controls.List;
import fl.controls.TextInput;
import fl.controls.dataGridClasses.DataGridColumn;
//import fl.controls.ProgressBar;
import fl.controls.ScrollPolicy;
import fl.data.DataProvider;
//import flash.display.Stage;
//import flash.display.StageAlign;
//import flash.display.StageScaleMode;
//import flash.net.navigateToURL;
import fl.events.ListEvent;
import fl.events.ComponentEvent;
var strHelper = new StringHelper(); // used for String::trim(); this isn't built into AS3 
A plethora (yay thesaurus!) of import statements for you.  On to make the DataGrid!


Making the DataGrid

 

var dp:DataProvider;

/**
* Instantiate the DataGrid
*/
var myDataGrid:DataGrid = new DataGrid();
myDataGrid.horizontalScrollPolicy = ScrollPolicy.ON;
myDataGrid.setSize(600, 300);
myDataGrid.setStyle("cellRenderer", AlternatingRowColors);
myDataGrid.move(10,185);
myDataGrid.rowCount = 4;//datagrid should only have 12 rows
addChild(myDataGrid);//add to dataGrid_mc not root

myDataGrid.addEventListener(ListEvent.ITEM_DOUBLE_CLICK, onDoubleClick);

/**
* Double Click on the dataGrid
*/
function onDoubleClick(e:ListEvent):void
{
var index:int = e.index;
var car:Object = e.item as Object;
trace(car.Year + " " + car.Make + " " + car.Model);
trace("ID:\t\t"+car.ID);
trace("Make:\t" + car.Make);
trace("Model:\t" + car.Model);
trace("Year:\t" + car.Year);
trace("HP:\t\t" + car.HP);

trace("Options:");

//Get only options from this car
var newXMLList:XMLList = xmlDP.Cars.(ID == car.ID).Options.Value;

var optionString:String = "";
for each (var item:XML in newXMLList)
{
if (optionString != "")
optionString += ", ";
optionString += item;
}

trace(optionString);
}

/**
* Instantiate DataGridColumns
*/
function addDataGridColumn(name:String, header:String, width:Number, minWidth:Number, isNumeric:Boolean = false):void
{
var column:DataGridColumn = new DataGridColumn(name);
column.headerText = header;
column.width = width;
column.minWidth = minWidth;

if(isNumeric)
{
column.sortOptions = Array.NUMERIC;
column.cellRenderer = RightAlignCell;
}

myDataGrid.addColumn(column);
}

addDataGridColumn("Make", "Make", 100, 100);
addDataGridColumn("Model", "Model", 100, 100);
addDataGridColumn("Year", "Year", 50, 50, true);
addDataGridColumn("HP", "Horse Power", 50, 50, true);
 


Loading the XML
 
/**
* Loading an external XML file
*/
var xmlDP:XML;
var xmlListData:XML;
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, dataCompleteHandler);
xmlLoader.addEventListener(ProgressEvent.PROGRESS, onProgress);
xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, catchIOError);
xmlLoader.load(new URLRequest("Cars.xml"));

/**
* Once the XML file is done loading it will set the datagrid to read the
* dataprovider set by the xml file.
*/
function dataCompleteHandler(event:Event):void
{
var ldr:URLLoader = event.currentTarget as URLLoader;
xmlDP = new XML(ldr.data);

dp = new DataProvider(xmlDP);//instantiate dataprovider
myDataGrid.dataProvider = dp;//assign dataprovider to datagrid

setList(xmlDP.Cars.Make, makeList);
setList(xmlDP.Cars.Model, modelList);
setList(xmlDP.Cars.Year, yearList, true);
//setList(xmlDP.Cars.HP, hpList, true); //range values instead of actual values in grid
hpList.addItem({label:"All", data:"All"});

hpList.addItem({label:"Under 100", data:"Under 100"});
hpList.addItem({label:"100 - 149", data:"100 - 149"});
hpList.addItem({label:"150 - 199", data:"150 - 199"});
hpList.addItem({label:"200 - 249", data:"200 - 249"});
hpList.addItem({label:"250 to 299", data:"250 to 299"});
hpList.addItem({label:"300 or more", data:"300 or more"});

hpList.allowMultipleSelection = true;

setList(xmlDP.Cars.Options.Value, optionList)
}

/** If a value is added to the DataGrid then it is added to it's list accordingly.
* There is no way to search for a value that is NOT in the DataGrid.
*/
function setList(newXMLList:XMLList, list:List, isNumeric:Boolean = false):void
{
var dp_array:Array = new Array();
for each (var item:XML in newXMLList)
{
var found:Boolean = false;
for(var i:int = 0; i < dp_array.length; i++)
{
if(item[0] == dp_array[i].label)
found = true;
}
if( ! found)
dp_array.push({label:item, data:item});
}

if(isNumeric)
{
dp_array.sortOn("label", Array.NUMERIC);
list.setStyle("cellRenderer", RightAlignCell);
}
else
dp_array.sortOn("label");

//crude way to add "All" to the top after sorting, there probably is a method
//to add a value to the front of the array, but this works.
dp_array = dp_array.reverse();
dp_array.push({label:"All", data:"All"});
dp_array = dp_array.reverse();

list.allowMultipleSelection = true;
list.dataProvider = new DataProvider(dp_array);
}


/**
* Show that XML file is not found.
*/
function catchIOError(event:IOErrorEvent)
{
trace(event.text);
}

/**
* Show progress of XML loading
*/
function onProgress(e:ProgressEvent):void
{
var percent:Number = (e.bytesLoaded / e.bytesTotal) * 100;
trace("Loading..." + percent.toString(10) + "%");
}

The Exported XML

 If you have Microsoft Office Access 2007, download the zip file and open up the .accdb file.  I didn't use a .mdb file but that can also be used to export XML.  All you really need to know is that XML has to be used instead of an actual database file.  If you're using MySQL just use php to show the database as XML.  

Back to the .accdb file, once opened you'll see how to constrain the Options field to certain values.  This is what MSAccess2007 exports.




6
Nissan
Maxima
2009

4 Wheel Disc Brakes


Power Doorlocks


Power Windows


Sun roof

290


1
Toyota
Celica GT-S
2000

4 Wheel Disc Brakes


Power Doorlocks


Power Windows


Sun roof

180


2
Toyota
Celica ST
1996

Power Doorlocks


Power Windows

105


3
Nissan
350Z
2009

4 Wheel Disc Brakes


Power Doorlocks


Power Windows


Sun roof

306


4
Honda
Civic Si
2000

4 Wheel Disc Brakes


Power Doorlocks


Power Windows


Sun roof

160


5
Honda
S2000
2009

4 Wheel Disc Brakes


Power Doorlocks


Power Windows

237


 

 


Creating Inputs, Lists, and Labels

All this code really does is instantiate labels, inputs, and lists, which could actually be drawn on the stage with less code, but I have already written the code.

 
 
//---------------------------
var textInput:TextInput = new TextInput();
textInput.move(10, 150);
textInput.width = 220;

//Press the enter key to apply filter (search)
textInput.addEventListener("enter",changeHandler);
//Everytime the input box is changed, apply filter (search)
//(can affect performance)
textInput.addEventListener(Event.CHANGE, changeHandler);

textInput.tabIndex = 0;
addChild(textInput);

var textInputLabel:Label = new Label();
textInputLabel.text = "Search grid";
textInputLabel.move(textInput.x + 5, textInput.y - 20);
textInputLabel.autoSize = TextFieldAutoSize.LEFT;
addChild(textInputLabel);

//---------------------------
var makeList:List = new List();
makeList.move(10,40);
makeList.width = 100;
makeList.rowCount = 4;
makeList.addEventListener(Event.CHANGE, changeHandler);
makeList.tabIndex = 1;
addChild(makeList);

var makeLabel:Label = new Label();
makeLabel.htmlText = "Make";
makeLabel.move(makeList.x + 5, makeList.y - 20);
makeLabel.autoSize = TextFieldAutoSize.LEFT;
makeList.tabIndex = 2;
addChild(makeLabel);

//---------------------------
var modelList:List = new List();
modelList.move(makeList.x + makeList.width + 10, 40);
modelList.width = 125;
modelList.rowCount = 4;
modelList.addEventListener(Event.CHANGE, changeHandler);
addChild(modelList);

var modelLabel:Label = new Label();
modelLabel.htmlText = "Model";
modelLabel.move(modelList.x + 5, modelList.y - 20);
modelLabel.autoSize = TextFieldAutoSize.LEFT;
addChild(modelLabel);

//---------------------------
var yearList:List = new List();
yearList.move(modelList.x + modelList.width + 10, 40);
yearList.width = 65;
yearList.rowCount = 4;
yearList.addEventListener(Event.CHANGE, changeHandler);
addChild(yearList);

var yearLabel:Label = new Label();
yearLabel.htmlText = "Year";
yearLabel.move(yearList.x + 5, yearList.y - 20);
yearLabel.autoSize = TextFieldAutoSize.LEFT;
addChild(yearLabel);

//---------------------------
var hpList:List = new List();
hpList.move(yearList.x + yearList.width + 10, 40);
hpList.width = 85;
hpList.rowCount = 3;
hpList.addEventListener(Event.CHANGE, changeHandler);
addChild(hpList);

var hpLabel:Label = new Label();
hpLabel.htmlText = "Horsepower";
hpLabel.move(hpList.x+5, hpList.y - 20);
hpLabel.autoSize = TextFieldAutoSize.LEFT;
addChild(hpLabel);

//---------------------------
var optionList:List = new List();
optionList.move(hpList.x + hpList.width + 10, 40);
optionList.width = 135;
optionList.rowCount = 4;
optionList.addEventListener(Event.CHANGE, changeHandler);
addChild(optionList);

var optionLabel:Label = new Label();
optionLabel.htmlText = "Options";
optionLabel.move(optionList.x + 5, optionList.y - 20);
optionLabel.autoSize = TextFieldAutoSize.LEFT;
addChild(optionLabel);

//---------------------------
 

Array Filters (for DataProviders)

There was one filter for the text input already written in the livedocs on adobe.com.  The others that I wrote were derived from this in order to derive more filters using the lists.  Each filter is a different example of how a filter can be used.

 
/* Handler function for the TextInput component instance. This function converts the
data provider (dp) to an array using the DataProvider class's toArray() method, and
then filters the newly created array using the Array class's filter() method. Finally,
the data grid's data provider property is set to the contents of the filtered array. */
function changeHandler(event:Event):void
{
//apply the name filter
var arr:Array = dp.toArray();
var filteredArr:Array = arr.filter(textInputFilter);
filteredArr = filteredArr.filter(makeFilter);
filteredArr = filteredArr.filter(modelFilter);
filteredArr = filteredArr.filter(yearFilter);
filteredArr = filteredArr.filter(optionFilter);
filteredArr = filteredArr.filter(hpFilter);
myDataGrid.dataProvider = new DataProvider(filteredArr);
trace(myDataGrid.dataProvider.length + " entries relative.");
}

//comment provided by Adobe.com
/* This function is called by the changeHandler() function and is used to filter the
contents of an array. This function takes the current contents of the TextInput
component instance and compares the contents against the current item in the array.
If the strings match, the nameFilter() method returns true and the current
item is added to the new array. If the strings do not match, the method returns
false and the item is not added. */

/* My comment: It is able to add delimiters for the search. In order to have it be a
keyword search there must be an explode function, called Split. This function returns
an Array of all the words separated by the delimiter. There could also be special
cases where 'OR' or 'AND' can be used as delimiters for more advanced searching.

for more information refer to:
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/String.html
*/
function textInputFilter(obj:Object, idx:int, arr:Array):Boolean
{
if(textInput.text == "")
return true; //nothing to search

//This will make one string out of every piece of data from the XML file. Not from
//the DataGrid. This just filters the DataProvider of the DataGrid to show results
if(obj.Make)
{
var searchable:String = obj.Name;

if(obj.Make) searchable += " " + obj.Make;
if(obj.Model) searchable += " " + obj.Model;
if(obj.Year) searchable += " " + obj.Year;
if(obj.HP) searchable += " " + obj.HP;

//get all values from one row of values
var newXMLList:XMLList = xmlDP.Cars.(ID == obj.ID).Options.Value;
if(newXMLList)
{
var optionString:String = "";
//create one long string of options separated by spaces
for each (var item:XML in newXMLList)
optionString += " " + item;
searchable += " " + optionString;
}

if (searchable.toLowerCase().search(textInput.text.toLowerCase()) >= 0)
{
return true; // search value has been found!
}
}
return false; //value not found
}

function makeFilter(obj:Object, idx:int, arr:Array):Boolean
{
//if no items are selected in the list
if(makeList.selectedItems.length == 0) return true;
//if "ALL" is selected in the list
if(makeList.selectedItems[0].data == "All") return true;

//if the row actually has something in the Make field
if(obj.Make)
{
//take the selected items
var searchTerms:Array = makeList.selectedItems;
//and the Make
var searchable:String = obj.Make;
//and search the selected items for the Make!
for each(var searchTerm:Object in searchTerms)
if(searchable == searchTerm.data)
return true; //search term found!
//nothings found!
}
return false;
}

function hpFilter(obj:Object, idx:int, arr:Array):Boolean
{
if(hpList.selectedItems.length <= 0) return true; // no items selected
if(hpList.selectedItems[0].data == "All") return true;

if(obj.HP)
{
var hp:Number = obj.HP;
var selections = hpList.selectedItems;

for (var i:int = 0; i
{
var txt1:String = selections[i].data;
trace(hp + " : " + selections[i].data);
switch (txt1)
{
case "Under 100" :
if (hp < 100)
return true;
break;
case "100 - 149" :
if (hp >= 100 && hp < 150)
return true;
break;
case "150 - 199" :
if (hp >= 150 && hp < 200)
return true;
break;
case "200 - 249" :
if (hp >= 200 && hp < 250)
return true;
break;
case "250 to 299" :
if (hp >= 250 && hp < 300)
return true;
break;
case "300 or more" :
if (hp >= 300)
return true;
break;

case "All" :
return true;
}
}
}
return false; // hp year field DNE
}

function modelFilter(obj:Object, idx:int, arr:Array):Boolean
{
if(modelList.selectedItems.length == 0) return true;
if(obj.Model)
{
return searchStringInArray(modelList.selectedItems, obj.Model, "All");
}
else
{
if(modelList.selectedItems.length > 0)
if(modelList.selectedItems[0].data == "All")
return true;
}

return false;
}

/** These items aren't actually in the datagrid but they still can be searched for
* using the options in the list.
*/
function optionFilter(obj:Object, idx:int, arr:Array):Boolean
{
if(optionList.selectedItems.length == 0) return true;
//create a list of all key elements at each car's (search by ID)
var newXMLList:XMLList = xmlDP.Cars.(ID == obj.ID).Options.Value;

if(newXMLList)
{
var optionString:String = "";

//create one long string of key elements separated by commas
for each (var item:XML in newXMLList)
{
if (optionString != "")
optionString += ", ";
optionString += item;
}

return searchStringInArray(optionList.selectedItems, optionString, "All");
}
return false;
}

function yearFilter(obj:Object, idx:int, arr:Array):Boolean
{
/*
//if no items are selected in the list
if(yearList.selectedItems.length == 0) return true;
//if "ALL" is selected in the list
if(yearList.selectedItems[0].data == "All") return true;

//if the row actually has something in the year field
if(obj.Year)
{
//take the selected items
var searchTerms:Array = yearList.selectedItems;
//and the year
var searchable:String = obj.Year;
//and search the selected items for the year!
for each(var searchTerm:Object in searchTerms)
if(searchable == searchTerm.data)
return true; //search term found!
}
return false; //nothings found!

*/

if(yearList.selectedItems.length == 0) return true;
if(obj.Year)
{
return searchStringInArray(yearList.selectedItems, obj.Year, "All");
}
else
{
if(yearList.selectedItems.length > 0)
if(yearList.selectedItems[0].data == "All")
return true;
}

return false;


}

// will return true or false if any string in selections is in searchable
function searchStringInArray(searchTerms:Array, searchable:String, omniString:String = "All"):Boolean
{
if(searchTerms.length > 0)
{
if(searchTerms[0].data == omniString) return true;

if(searchable)
{
for each(var searchTerm:Object in searchTerms)
if(searchable.search(strHelper.trim(searchTerm.data," ")) >= 0)
return true; //search term found!
}
}
else
return true; // nothing is selected
return false; // nothing has been found
}
 

 


View the Example

 

 

 

Files: cars.zip

 

 

 

 

References:

Comments
Add New Search
Datagrid
Houndawg (67.49.2.xxx) 2009-01-12 18:51:52

Great Job.
This is exactly what I was looking for.

I hope it works for me like it
does in the example.

Question: How would you go about adding a image
and/or a movie to this example.
CellRenderer
drooza (SAdministrator) 2009-01-17 22:18:47

Use CellRenderer

http://www.sephiroth.it/tutorials/flashPHP/cell...
Errerem carnt read
Anonymous (82.42.145.xxx) 2009-02-05 08:28:30

this is just what I want but i carnt read how to do kt because am a starter in
the flash 8 fingy
dynamic grid...
renzo (125.163.76.xxx) 2009-03-15 01:35:32

does anyone know how to edit the value at grid...
how to play video when cell is clicked?
Jason (86.29.128.xxx) 2009-05-02 22:15:43

how would you make a video play in flash when a cell is clicked in the datagrid?
im guessing a function but would you know the exact code and where it gets
placed in the AS??

thanks
Anonymous (82.75.150.xxx) 2009-06-16 07:19:54

Is there a way to work with several xml-
files; here for instance one for
cars,
one for truck, one for motorbikes.

Depending on what the visitor is
looking
for, the data inside the xml-files in question should be read into
the
datagrid and the queries set for All.

The visitor can 'jump' between each
of
the sections (eg by using a combobox
and the grid gets filled up with the
new
data from the other xml-file
immediately.

I realy would like to have seperate

xml-files for each of the needs of
the visitor...

Thank you very much in
advance
change data provider
drooza (SAdministrator) 2009-06-18 19:24:09

What you can do is just change the dataprovider of the datagrid to another xml
file.

check out how it's filtered. since the dataprovider is changed to an
array for filtering, you can just filter a different dataprovider.
atul singh (61.16.244.xxx) 2009-07-02 00:09:56

very nice
thanks for lot of work

Regards
Atul singh
Anonymous (74.103.209.xxx) 2010-02-05 01:46:17

Nicely done.
I am trying to figure how can I insert URL and get it to work.
Question
James (95.17.50.xxx) 2010-03-14 07:57:02

Really top notch tutorial, congratulations. I'm trying to take it a bit further
but I need a bit of help. How can I use the filter to load a corresponding image
into a UIloader - I think the problem I'm having is that logically the image can
only appear when the user has filtered down to only one unique result in the
data grid, but I can't see what the value of the result would be in action
script, or what to set an event listener for.
then I suppose it is a simple
question of: -loader.source=that value+".png"
If you don't think this is
the way please tell me what you think
Thanks in advance and keep up the good
work - we need you!
Write comment
Name:
Email:
 
Title:
UBBCode:
[b] [i] [u] [url] [quote] [code] [img] 
 
:angry::0:confused::cheer:B)
:evil::silly::dry::lol::kiss:
:D:pinch::(:shock::X
:side::):P:unsure::woohoo:
:huh::whistle:;):s:!:
:?::idea::arrow:
Please input the anti-spam code that you can read in the image.

3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved."

Last Updated ( Friday, 07 November 2008 12:00 )
 

Make a Donation!

Advertisement
Banner

HomeProjectsSnippetsContact Me

Copyright © 2008, Drooza.com