Friday, July 03, 2009    
Home My Books Blog ColdFusion About Me Back    

Calendar
<< Jul 2006 >>
S M T W T F S
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

Search

Categories
 • Acrobat (3) [RSS]
 • Adobe (76) [RSS]
 • AdobeMAX06 (45) [RSS]
 • AdobeMAX07 (59) [RSS]
 • AdobeMAX08 (66) [RSS]
 • AdobeMAX09 (10) [RSS]
 • AIR (190) [RSS]
 • Appearances (175) [RSS]
 • Books (70) [RSS]
 • CFEclipse (14) [RSS]
 • ColdFusion (1277) [RSS]
 • Data Services (28) [RSS]
 • Fish Tank (3) [RSS]
 • Flash (144) [RSS]
 • Flex (458) [RSS]
 • Home Automation (3) [RSS]
 • Jobs (113) [RSS]
 • JRun (13) [RSS]
 • Labs (35) [RSS]
 • LiveCycle (30) [RSS]
 • MAX (205) [RSS]
 • Mobile (103) [RSS]
 • Regular Expressions (17) [RSS]
 • RIA (17) [RSS]
 • SQL (39) [RSS]
 • Stuff (524) [RSS]
 • Tips (CF Studio) (80) [RSS]
 • Tips (CF) (795) [RSS]
 • Tips (Dreamweaver) (91) [RSS]
 • Tips (Flex Builder) (2) [RSS]
 • Using CF (154) [RSS]

Other BLOGs
 • Charlie Arehart
 • Lee Brimelow
 • Ray Camden
 • Christophe Coenraets
 • Sean Corfield
 • Mihai Corlan
 • Cornel Creanga
 • Mark Doherty
 • John Dowdell
 • Danny Dura
 • Enrique Duvos
 • Steven Erat
 • Kevin Hoyt
 • Serge Jespers
 • Adam Lehman
 • Duane Nickull
 • Miti Pricope
 • Andrew Shorten
 • Ryan Stewart
 • James Ward
 • Greg Wilson
 • Full As A Goog

RSS Feeds
 • Feed
 • Subscribe

Join my mailing list and find out about new books and other topics of interest.

Thoughts, ideas, tips, musings, and pontifications (not necessarily in that order) by Ben Forta ...
NOTE: This is my personal blog, and the opinions and statements voiced here are my own.

Viewing By Entry / Main
July 13, 2006

Filtering Data In Flex

This afternoon a user IMed me to ask for help with a ColdFusion powered Flex 2 application. He wanted to be able to perform on-the-fly filtering of data in a CF populated Flex DataGrid control. Here is the solution I sent him.

Populate the DataGrid with an ArrayCollection (converting the data to an ArrayCollection if needed). ArrayCollection has a property named filterFunction (well, technically filterFunction is a property of listCollectionView of which ArrayCollection is a subclass) which takes the name of a function to be used to filter data. Each time ArrayCollection contents are refreshed this passed function will be called, once per ArrayCollection item. If the function returns true then the item is included, if false then it is excluded. So, to filter DataGrid contents on-the-fly, simple define a filter function that performs the filtering you need, and call ArrayCollection.refresh() as the filter text changes.

Here is a complete example. In the interests of simplicity this uses a local ArrayCollection (as opposed to data returned from ColdFusion) and will run as is. ArrayCollection myData is the dataProvider for the DataGrid. Function processFilter() is the filter function, it accepts an object and returns true or false based on whether it is a match or not (this filter function looks for substrings in a single column, and this could be changed of course). The TextInput box is where filter text is entered, and the change event simply calls myData.refresh() which forces the filter function to be reapplied to the ArrayCollection.

It is worth noting that filterFunction should not be specified until the ArrayCollection has been populated (or you'll get a null reference error). So, if you are using RemoteObject to invoke a CFC method to return data to populate an ArrayCollection, you should not set filterFunction until data has been returned. As such, you may want to do this in a RemoteObject result handler.

Here's the code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                layout="vertical" creationComplete="initApp()">


    <mx:Script>
    <![CDATA[

    // On startup

    public function initApp():void
    {

        // Set filter function
        // Be careful to set filterFunction
        // only after ArrayCollection has been
        // populated.

        myData.filterFunction=processFilter;
    }
        
    // Filter function

    public function processFilter(item:Object):Boolean
    {
        var result:Boolean=false;

        // If no filter text, or a match, then true

        if (!item.name.length
            || item.name.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >
= 0)
            result=true;
                
        return result;
    }
    ]]>

    </mx:Script>

    <!-- Data (use ArrayCollection) -->
    <mx:ArrayCollection id="myData">
        <mx:source>
            <mx:Object name="Ben Forta" location="Oak Park, MI" phone="(248)555-5555" />
            <mx:Object name="Jane Doe" location="New York, NY" phone="(212)555-1234" />
            <mx:Object name="Jim Jones" location="Atlanta, GA" phone="(414)555-1212" />
            <mx:Object name="Roberta Roberts" location="Chicago, IL" phone="(312)555-4321" />
            <mx:Object name="Steve Stevens" location="Boston, MA" phone="(617)555-5656" />
        </mx:source>
    </mx:ArrayCollection>

    <!-- UI -->
    <mx:HBox width="100%">
        <mx:Label text="Filter:"/>
        <mx:TextInput id="txtFilter" width="100%"
                        change="myData.refresh()"/>

    </mx:HBox>
    <mx:DataGrid dataProvider="{myData}"
                    width="100%" height="100%">

        <mx:columns>
            <mx:DataGridColumn headerText="Name"
                                dataField="name"/>

            <mx:DataGridColumn headerText="Location"
                                dataField="location"/>

            <mx:DataGridColumn headerText="Phone"
                                dataField="phone"/>

        </mx:columns>
    </mx:DataGrid>
    
</mx:Application>

Related Blog Entries

TrackBacks
There are no trackbacks for this entry.

No trackback URL. Trackbacks are only allowed via interactive form.

Comments
Cool. The use of ArrayCollection in Flex is one of the best new features because of its inherited methods; a lot less looping through arrays now;)

Oliver
# Posted By Oliver Merk | 7/14/06 12:16 PM
Good example! I'm interested in performance of the filtering.
So, I made a stupid sample.

http://shigeru-nakagaki.com/index.cfm/2006/7/15/20...
# Posted By Shigeru | 7/14/06 3:00 PM
Shigeru, I'd not load 100,000 rows into a DataGrid, that is what paging is for.

--- Ben
# Posted By Ben Forta | 7/14/06 3:07 PM
Nice example. Just one thing, i tried to apply the filter on a column containing numbers, but it doesn't work. I have to convert to String ?
# Posted By Cyril | 7/17/06 8:46 AM
Oups... forget it, it works perfectly ! :-) I think i really need holidays...
# Posted By Cyril | 7/17/06 9:07 AM
Hello Ben,

fyi - clicking on comments(#) on a blog entry 'popups' comment window (where I am writing this) but does not show comments on top when they exists...
# Posted By Mario Talavera | 7/19/06 10:17 AM
I'm using the coldfusion wizard in flexbuilder 2 to build my app. Where would I place this code to work with the auto generated code.
here is my grid component code:
<?xml version="1.0" encoding="utf-8"?>
<cfComponents:SizeableTitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"; xmlns="*"
   xmlns:cfComponents="com.adobe.ColdFusion.components.*"
   creationComplete="initComponent()"
   title="Legend"
   showCloseButton="true" close="WindowManager.remove(this);" >
   <cfComponents:states>
      <mx:State name="find">
         <mx:AddChild relativeTo="{hbox1}" position="before">
            <mx:HBox width="100%">
               <mx:Label text="Search"/>
               <mx:TextInput id="txtFilter"/>
               <mx:Button label="Button"/>
            </mx:HBox>
         </mx:AddChild>
      </mx:State>
   </cfComponents:states>

   <mx:Script>
      <![CDATA[
         import com.adobe.windowedApplication.managers.WindowManager;
         import mx.core.UIComponent;
         import mx.collections.ArrayCollection;
         import mx.utils.ObjectUtil;
         import mx.controls.Alert;
         import mx.rpc.events.FaultEvent;
         import mx.rpc.events.ResultEvent;
         import com.cfgenerated.views.detail.detail;
         private var currentIndex:int = 0;

         private var _key:Object;

         [Bindable]
         public function get key():Object
         {
            return this._key;
         }
         public function set key(key:Object):void
         {
            this._key = key;
         }

         private function initComponent():void
         {
            refreshList(null);
         }

         public function refreshList(event:Event):void
         {
            this.dataManager.getMasterQuery(this.key);
         }

         private function deleteItem(key:Object):void
         {
            this.dataManager.deleteItem(key);
         }

         private function getDetailComponent(key:Object):UIComponent
         {
            var view:detail = new detail();
            view.key = key;
            view.addEventListener("change", refreshList);
            return view;
         }

         /**
          * RemoteObject result and error handlers
          */
         private function server_fault(event:FaultEvent):void
         {
            // dump error message
            Alert.show( ObjectUtil.toString(event.fault) );
         }

         private function getMasterQuery_result(event:ResultEvent):void
         {
            //Alert.show( ObjectUtil.toString(event.result) );
            this.masterList.dataProvider = event.result as ArrayCollection;
            this.masterList.selectedIndex = this.currentIndex;
         }

         private function deleteItem_result(event:ResultEvent):void
         {
            //Alert.show( ObjectUtil.toString(event.result) );
            refreshList(null);
         }
      ]]>
   </mx:Script>

   <mx:RemoteObject
      id="dataManager"
      showBusyCursor="true"
      destination="ColdFusion" source="Legend.components.cfgenerated.Legend">
      <mx:method name="getMasterQuery" result="getMasterQuery_result(event)" fault="server_fault(event)" />
      <mx:method name="deleteItem" result="deleteItem_result(event)" fault="server_fault(event)" />
   </mx:RemoteObject>

   <mx:HBox id="addEditDeleteToolbar">
      <mx:Spacer width="100%"/>
      <mx:Button id="addBtn"
         icon="@Embed(source='../../../../images/add.png')" width="40"
         click="WindowManager.add( getDetailComponent(null), this, false );" toolTip="Add" />
      <mx:Button id="editBtn"
         icon="@Embed(source='../../../../images/edit.png')" width="40"
         enabled="{this.masterList.selectedIndex>=0}"
         click="WindowManager.add( getDetailComponent(this.masterList.selectedItem.ID), this, false );" toolTip="Edit" />
      <mx:Button id="deleteBtn"
         icon="@Embed(source='../../../../images/delete.png')" width="40"
         enabled="{this.masterList.selectedIndex>=0}"
         click="this.deleteItem(this.masterList.selectedItem.ID)" toolTip="Delete" />
      <mx:Button id="printBtn"
         icon="@Embed(source='../../../../images/print.png')" width="40"
         click="navigateToURL(new URLRequest('http://192.168.10.18/lookup/printabbrev.cfm'));" toolTip="Print" />
      <mx:Button id="searchBtn"
         icon="@Embed(source='../../../../images/search.png')" width="40"
         click="currentState='find'" toolTip="Search" />
   </mx:HBox>

   <mx:HBox width="100%" height="100%" id="hbox1">
      <mx:DataGrid
         id="masterList"
         doubleClickEnabled="true"
         doubleClick="this.currentIndex=this.masterList.selectedIndex; if(this.masterList.selectedItem!=null) { WindowManager.add( getDetailComponent(this.masterList.selectedItem.ID), this, false ); }"
         width="100%" height="400" top="0" left="0" right="0" bottom="0">
         <mx:columns>
            <mx:DataGridColumn dataField="abbrev" headerText="Abbrev" width="100" />
            <mx:DataGridColumn dataField="short_desc" headerText="Short Desc" width="400" />
            
         </mx:columns>
      </mx:DataGrid>

   </mx:HBox>

</cfComponents:SizeableTitleWindow>
# Posted By carlosM() | 8/4/06 5:11 PM
Hi Ben,

I am using remoteobject to get the data in the grid and used the filterfunction in the result handler, however i'm getting Cannot access a property or method of a null object reference.

I thought this was supose to prevent this error.

Thanks,
Joseph.
# Posted By Joseph Abenhaim | 8/8/06 7:48 PM
Joseph, I only got that error when I had a filter function set before I got data back. When I set it in the result handler the error went away. So you may be seeing the error from a different location.

--- Ben
# Posted By Ben Forta | 8/8/06 9:00 PM
Ben,

Heres the code that i use i dont know whats going on with this but i get the error no matter what i do. the data displays ok in the grid, its only when i type something in the text field.

   <mx:Script>
    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.rpc.events.ResultEvent;
         import mx.controls.Alert;
         
         [Bindable]
         public var gridData:ArrayCollection = null;
   
    // component init
    private function initComponent():void {
       
       dataService.test();
       
    }
   
    public function processFilter(item:Object):Boolean {
            var result:Boolean=false;

            // If no filter text, or a match, then true
            if (!item["city"].length || item["city"].toUpperCase().indexOf(txtSearchLog.text.toUpperCase()) >= 0)
               result=true;
            return result;
         }
       
         private function getData_resultHandler(event:ResultEvent):void {
         
            gridData = event.result as ArrayCollection;
            dataGrid.dataProvider = gridData;
            gridData.filterFunction=processFilter;
            
         }

   
    ]]>
   </mx:Script>
   <mx:RemoteObject id="dataService" destination="ColdFusion" source="zonebooks.bin.components.test" showBusyCursor="true">
      <mx:method name="test" result="getData_resultHandler(event)" fault="Alert.show(event.fault.message)"/>
   </mx:RemoteObject>
   
   <mx:Canvas width="100%" height="100%">
   
      <mx:Label x="10" y="12" text="Search"/>
    <mx:TextInput right="10" left="67" y="10" change="gridData.refresh();" id="txtSearchLog"/>
    <mx:DataGrid id="dataGrid" bottom="10" top="38" right="10" left="10" draggableColumns="false" sortableColumns="false"/>
   
   </mx:Canvas>
   
   <mx:ControlBar>
      <mx:Spacer width="100%"/>
      <mx:Button label="Show Options" id="button1" click="parentDocument.currentState= 'Click'" />
   </mx:ControlBar>

</mx:Panel>
# Posted By Joseph Abenhaim | 8/9/06 9:47 AM
Hey Ben,

I think this function works a bit better. The way you have written the function entering "en" in the textfield matches "Ben Forta". While this may be what the user wants, I think generally people are looking for a match from the beginning of the strings.

I'm using a RegEx here to do just that:

public function processFilter(item:Object):Boolean
{
var result:Boolean=false;
var pattern:RegExp = new RegExp("^"+txtFilter.text,"i");
// If no filter text, or a match, then true
if (!item.name.length || item.name.match(pattern))
result=true;
return result;
}

Gus
# Posted By Steve Gustafson | 8/15/06 5:24 AM
What about using a changeWatcher to watch for the arrayCollection to change(be populated);
I am passing my data that is returned from the cfc into another component, so I can't set the filterFunction in the result function.
So in my componet I set a watcher

private function init():void{
   watcher = ChangeWatcher.watch(this, ["regData"], dataLoaded);
}
then in the dataLoaded function set the filterFunction
private function dataLoaded(event:PropertyChangeEvent):void{
   regData.filterFunction=processFilter;
   watcher.unwatch();
}

It works, I am just not sure if it is good practice.

Russ
# Posted By Russ | 8/16/06 3:31 PM
Ben,
I have a grid that gets filled with data just fine. When I try and apply your sample to my grid for filteing I get am error
I am calling in the data using the mx:remoteobject with id="myData":
Cant assign operations into an RPC Service(filterFunction)
Im not sure what that means. If I continue and try to use the filter I get:
faultstring="The method 'refresh' could not be found in component"
any thoughts?
Thanks
George
# Posted By George Smith | 8/16/06 7:06 PM
Ben,
I am closer to figuring this out. What I cant seem to do is figure out how to make the call from the RemoteObject into an ArrayCollection. I see how you have the ArrayCollection and if I type in what you have change the variables it works in my app. But if I use the RemoteObject to call to the cfc I fill the grid also, but It wont filter, then and I get a: Cannot access a property or methed of a null object. Error. Is there a sample of ArrayCollection vs. RemoteObject?
# Posted By George | 8/17/06 12:30 PM
George when you assign the results form a cfc to a variable, you need to tell it to assign as an ArrayCollection

Here is the result function for my cfc. I have a variable regData typed as an ArrayCollection that is the dataProvider for my dataGrid

public function handleRegResult(event:ResultEvent):void{
   regData = event.result as ArrayCollection;   
}

Then you have all of the sorting/ filtering objects of an ArrayCollection
# Posted By Russ | 8/17/06 12:40 PM
George,

This should be close to what you are looking for:

public var roArray:ArrayCollection;

private function getRemoteObjectResult(event:Object):void
{
   roArray = event.result as ArrayCollection;   
roArray.filterFunction=processFilter;
roArray.refresh();
   myDataGrid.dataProvider = roArray;
}

public function processFilter(item:Object):Boolean
{
   var result:Boolean=false;
   if (item.currentStatus == 1)
      result=true;
   return result;
}

In this example, I am filtering on roArray.currentStatus == 1

I hope this helps.

Gus
# Posted By Gus | 8/17/06 12:46 PM
Im stumped, here is what I have:

I think there is some extra stuff I dont need that is blocking this to work but im not sure. Thanks for looking.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="vertical" creationComplete="initApp()" >

   <mx:Script>
      <![CDATA[
         import mx.rpc.events.ResultEvent;
         import mx.controls.Alert;
         import mx.collections.ArrayCollection;
         
         [Bindable]
         public var myData:ArrayCollection;

         [Bindable]
public var aReturnTypes: Array = [ {label:"query", data:"query"} ];

         [Bindable]
         public var returnType:String="string";
         
         public function clearAll():void{
            
            myData=new ArrayCollection();   
         }
      
         public function handleQueryResult(event:ResultEvent):void{
            myData=event.result as ArrayCollection;   
         }
         
         
      ]]>
   </mx:Script>
   
   <mx:Script>
      <![CDATA[
         public function initApp():void
         {
            myData.filterFunction = processFilter;
            }
         public function processFilter(item:Object):Boolean
         {
            var result:Boolean=false;
            
            if (!item.PDES5W.length
            || item.PDES5W.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >= 0)
            result=true;
            
            return result;
         }
      ]]>
   </mx:Script>
   

   
   <mx:RemoteObject
      id="qResult"
      destination="ColdFusion"
      source="Inventory"
      showBusyCursor="true"
      >
         
         <mx:method name="Inventory" result="handleQueryResult(event)" fault="Alert.show(event.fault.message)"/>   
         
   </mx:RemoteObject>
   
   <mx:Panel title="Inventory" height="90%" width="100%"
paddingTop="5" paddingLeft="5" paddingRight="5" paddingBottom="5" cornerRadius="10" roundedBottomCorners="true">


<mx:HBox width="400">
      <mx:TextInput width="100" id="txtFilter" change="myData.refresh()" />
      <mx:RadioButton label="Warehouse" click="accordion.selectedIndex=0;" selected="true"/>
      <mx:RadioButton label="Cash / Carry" click="accordion.selectedIndex=1;"/>

</mx:HBox>

<mx:Accordion id="accordion" width="100%" height="100%" headerHeight="5">
<mx:VBox height="100%" >
   <mx:DataGrid dataProvider="{myData}" initialize="qResult.Inventory()" width="100%" height="100%">
       <mx:columns>
      

<mx:DataGridColumn dataField="PNUM5W" headerText="Prod ID" width="55"/>
<mx:DataGridColumn dataField="PDES5W" headerText="Desc" width="163"/>
<mx:DataGridColumn dataField="SDIVDE" headerText="Size" width="50"/>
<mx:DataGridColumn dataField="ISCF3W" headerText="Pac" width="35"/>
<mx:DataGridColumn dataField="DIVN5W" headerText="Rnk" width="35"/>

<mx:DataGridColumn dataField="INV_11" headerText="Or Inv" width="50"/>
<mx:DataGridColumn dataField="ORD_11" headerText="Or Ord" width="50"/>
<mx:DataGridColumn dataField="DAT_11" headerText="Or Due" width="50"/>
<mx:DataGridColumn dataField="INT_11" headerText="Or InT" width="50"/>

<mx:DataGridColumn dataField="INV_31" headerText="Ch Inv" width="50"/>
<mx:DataGridColumn dataField="ORD_31" headerText="Ch Ord" width="50"/>
<mx:DataGridColumn dataField="DAT_31" headerText="Ch Due" width="50"/>
<mx:DataGridColumn dataField="INT_31" headerText="Ch InT" width="50"/>

<mx:DataGridColumn dataField="INV_31" headerText="MH Inv" width="50"/>
<mx:DataGridColumn dataField="ORD_31" headerText="MH Ord" width="50"/>
<mx:DataGridColumn dataField="DAT_31" headerText="MH Due" width="50"/>
<mx:DataGridColumn dataField="INT_31" headerText="MH InT" width="50"/>

      </mx:columns>
   </mx:DataGrid>
   </mx:VBox>
   
   <mx:VBox height="100%" >
   <mx:DataGrid dataProvider="{myData}" initialize="qResult.Inventory()" width="100%" height="100%">
       <mx:columns>
<mx:Array>
<mx:DataGridColumn dataField="PNUM5W" headerText="Prod ID" width="55"/>
<mx:DataGridColumn dataField="PDES5W" headerText="Desc" width="163"/>
<mx:DataGridColumn dataField="SDIVDE" headerText="Size" width="50"/>
<mx:DataGridColumn dataField="ISCF3W" headerText="Pac" width="35"/>
<mx:DataGridColumn dataField="DIVN5W" headerText="Rnk" width="35"/>

<mx:DataGridColumn dataField="INV_11" headerText="Or Inv" width="50"/>
<mx:DataGridColumn dataField="ORD_11" headerText="Or Ord" width="50"/>
<mx:DataGridColumn dataField="DAT_11" headerText="Or Due" width="50"/>
<mx:DataGridColumn dataField="INT_11" headerText="Or InT" width="50"/>

<mx:DataGridColumn dataField="INV_31" headerText="Ch Inv" width="50"/>
<mx:DataGridColumn dataField="ORD_31" headerText="Ch Ord" width="50"/>
<mx:DataGridColumn dataField="DAT_31" headerText="Ch Due" width="50"/>
<mx:DataGridColumn dataField="INT_31" headerText="Ch InT" width="50"/>

<mx:DataGridColumn dataField="INV_31" headerText="MH Inv" width="50"/>
<mx:DataGridColumn dataField="ORD_31" headerText="MH Ord" width="50"/>
<mx:DataGridColumn dataField="DAT_31" headerText="MH Due" width="50"/>
<mx:DataGridColumn dataField="INT_31" headerText="MH InT" width="50"/>

</mx:Array>
      </mx:columns>
   </mx:DataGrid>
   </mx:VBox>
   </mx:Accordion>
   </mx:Panel>
</mx:Application>
# Posted By George | 8/17/06 12:59 PM
Gus,
What is the name of the remoteObject that you are using?
# Posted By George | 8/17/06 1:38 PM
Sorry Im posting so much there is no other source for this that I can find.

Is there a sample EXACTALY like the one provided, using the remoteObject instead of the ArrayCollection? I know the remoteObject needs to be called out into an ArrayObject, but how?
Thanks
# Posted By George | 8/17/06 2:37 PM
George,

Here is a full working example. To get this to work you only need to change path to the cfc in the remoteObject, and create and populate the table to query against:
Table Name: tblEmployee
Fields firstName varChar(),lastName varChar(),status varChar() ,currentStatus int

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="vertical" creationComplete="initApp()" height="460" width="800">
   <mx:Script>
      <![CDATA[
         import mx.collections.ArrayCollection;
    import mx.events.ListEvent;
    import mx.utils.ObjectUtil;
    [Bindable]
         public var empArray:ArrayCollection;
      ]]>
   </mx:Script>
<mx:Script>
    <![CDATA[
       // On startup
       public function initApp():void
       {
            exampleCFC.getEmpList();      
       }

         private function getEmpListResult(event:Object):void
         {
            empArray = event.result as ArrayCollection;   
          empArray.filterFunction=processFilter;
          empArray.refresh();
         }      
       // Filter function
       public function processFilter(item:Object):Boolean
       {
       var result:Boolean=false;
       var pattern:RegExp = new RegExp("^"+txtFilter.text,"i");
       // If no filter text, or a match, then true
       if ((!item.lastName.length && ObjectUtil.toString(item.currentStatus) == ObjectUtil.toString(Status.selectedValue)) || (ObjectUtil.toString(item.currentStatus) == ObjectUtil.toString(Status.selectedValue) && item.lastName.match(pattern)))
       result=true;
       return result;
       }
      
         public function showFault(fault:mx.rpc.Fault):void
         {
            mx.controls.Alert.show(fault.faultString +' '+ fault.faultDetail, 'Fault Alert Box', mx.controls.Alert.OK);
         }      
      ]]>
</mx:Script>
   <mx:RemoteObject
    id="exampleCFC"
    destination="ColdFusion"
    source="path.to.cfc"
      showBusyCursor="true">
      <mx:method name="getEmpList" fault="showFault(event.fault)" result="getEmpListResult(event)" />
   </mx:RemoteObject>   

<mx:Panel width="596" height="334" layout="absolute" horizontalCenter="-38.5" verticalCenter="0" title="Search Filter Example">
    <mx:VBox>
       <mx:HBox width="500">
       <mx:Label text="Employee Last Name:"/>
       <mx:TextInput id="txtFilter" width="203" change="empArray.refresh();"/>
       <mx:RadioButtonGroup id="Status" change="empArray.refresh();"/>
       <mx:RadioButton label="Active" groupName="Status" value='1' selected="true"/>
       <mx:RadioButton label="Inactive" groupName="Status" value='0'/>
       </mx:HBox>
       <mx:DataGrid dataProvider="{empArray}" width="501" height="263" x="10" y="77" id="employeeList">
       <mx:columns>
       <mx:DataGridColumn headerText="Last Name" dataField="lastName" width="200"/>
       <mx:DataGridColumn headerText="First Name" dataField="firstName" width="150"/>
       <mx:DataGridColumn headerText="Emp. ID" dataField="employeeID" width="100"/>
       <mx:DataGridColumn headerText="Status" dataField="status" width="100"/>
       <mx:DataGridColumn headerText="StatusID" dataField="currentStatus" width="100"/>
       </mx:columns>
       </mx:DataGrid>
    </mx:VBox>
</mx:Panel>
</mx:Application>


HERE IS THE CFC THAT IS CALLED:
<cfcomponent hint="Model For Filter Example" output="false">
   <cffunction name="getEmpList" returntype="Query" access="remote">
         <cfquery name="getEmployeeList" datasource="#application.ds#">
            SELECT e.employeeID,e.firstName,e.lastName,e.status,e.currentStatus
            FROM tblEmployee e
            ORDER BY e.LastName,e.FirstName
         </cfquery>
      <cfreturn getEmployeeList>
   </cffunction>
</cfcomponent>
# Posted By Gus | 8/18/06 7:58 AM
Gus and others,
Thanks alot, Gus your sample is a BIG help. I want to add a comboBox to the filter to choose the column to filter on. This is what I have but it does not work:
<mx:Script>
<![CDATA[
public function initApp():void
{
}

public function processFilter(item:Object):Boolean
{
var result:Boolean=false;
var pattern:RegExp= new RegExp("^"+txtFilter.text,"i");

// this is where I put the column header name like pnum5w instead of selected item (then it works for that column)

if (!item.selectedItem.data.length
|| item.selectedItem.data.match(pattern))
result=true;

return result;
}
]]>
</mx:Script>
<mx:Script>
<![CDATA[
//I want the data to represent the column like the first item, I think
public var myfilter: Array = [ {label:"Product ID", data:'PNUM5W'},
{label:"Description", data:2}, {label:"Size", data:3}, {label:"Pack", data:4} ];

public var selectedItem:Object;
]]>
</mx:Script>

<mx:Label text="Filter:"/>
<mx:TextInput width="100" id="txtFilter" change="myData.refresh()" />
<mx:ComboBox dataProvider="{myfilter}" width="125"
close="selectedItem=ComboBox(event.target).selectedItem"/>

<mx:DataGrid dataProvider="{myData}" initialize="qResult.Inventory()" width="100%" height="100%">
<mx:columns>

<mx:DataGridColumn dataField="PNUM5W" headerText="Prod ID" width="55"/>
<mx:DataGridColumn dataField="PDES5W" headerText="Desc" width="163"/>
<mx:DataGridColumn dataField="SDIVDE" headerText="Size" width="50"/>
<mx:DataGridColumn dataField="ISCF3W" headerText="Pac" width="35"/>
<mx:DataGridColumn dataField="DIVN5W" headerText="Rnk" width="35"/>
... there is more
Anythoughts

Thanks
George
# Posted By George | 8/18/06 1:26 PM
How come the Tile code works but the grid code does not work?

Where does the data. notation come from?

---------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml";
   creationComplete="catalogService.send()" viewSourceURL="srcview/index.html">

   <mx:Script>
      <![CDATA[
         private function filterProduct(item:Object):Boolean
         {
            return item.name.match(new RegExp("^" + brandText.text, "i"));

         }
      ]]>
   </mx:Script>
   <mx:HTTPService id="catalogService" url="http://127.0.0.1/scratch/Flex/FlexDemo/catalog.xml...;
      resultFormat="e4x" />
   <mx:XMLListCollection id="xlc"
      source="{catalogService.lastResult.*}"
      filterFunction="filterProduct" />
   <mx:Panel title="Product Catalog" width="380" height="385">
<!-- Begin Tile Code -->
      <mx:TileList dataProvider="{xlc}" width="100%" height="300"
         columnCount="2" rowCount="2">
         <mx:itemRenderer>
            <mx:Component>
               <mx:VBox paddingLeft="30" width="150" height="150"
                  horizontalScrollPolicy="off" verticalScrollPolicy="off">

                  <mx:Label text="{data.name}" />
                  <mx:Label text="{data.price}"/>
                  <mx:Label text="{data.brand}"/>                     
               </mx:VBox>
            </mx:Component>
         </mx:itemRenderer>
      </mx:TileList>
<!-- End Tile Code -->
<!-- Begin Grid Code -->
<!--      <mx:DataGrid dataProvider="{xlc}">
         <mx:columns>
            <mx:DataGridColumn dataField="{data.name}" headerText="Name"/>
            <mx:DataGridColumn dataField="{data.price}" headerText="Price"/>
            <mx:DataGridColumn dataField="{data.brand}" headerText="Brand"/>                           
            </mx:DataGridColumn>
         </mx:columns>
      </mx:DataGrid>
-->
<!-- End Grid Code -->
      <mx:ControlBar>
         <mx:Label text="Brand" />
         <mx:TextInput id="brandText" width="75"
            change="xlc.refresh()" />
      </mx:ControlBar>
   </mx:Panel>
</mx:Application>
# Posted By Rich | 8/23/06 9:53 AM
Hey all --

I keep getting stymied by components. I've been trying to get this to work in an example where the remote object is called in a main mxml document but the data grid and text input for the filtered text is in another component.

I finally got it to work by adding the initialization function to a button. Not very elegant, but nothing else I've tried is working (e.g., attaching it to a creationComplete in the component)

What would be the best way to make this initialize without the user having to start it?

Thanks,
Al
# Posted By Al Foote | 9/1/06 2:23 PM
Hello all.

I am trying to make this example work using a remote object as well. I know that I have to bind the data from the remote object to an ArrayCollection and then bind my datagrid to the ArrayCollection. I can not get it to work. Can someone please take a look.


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="vertical" creationComplete="initApp()">


   <!-- This tag calls the java class phonebook which is aliased in the remoting-config.xml file.
         It is set to an id of pb to be referenced in this app.-->
   <mx:RemoteObject id="pb" destination="phonebook" showBusyCursor="true" />
   <!-- End java class call tag -->
   
<mx:Script>
<![CDATA[

      import mx.collections.ArrayCollection;
      import mx.events.ListEvent;
      import mx.utils.ObjectUtil;

// On startup
public function initApp():void
{       
// Set filter function
// Be careful to set filterFunction only after ArrayCollection has been populated.
empData.filterFunction=processFilter;
}

// Filter function
public function processFilter(item:Object):Boolean
{
var result:Boolean=false;

// If no filter text, or a match, then true
if (!item.name.length
|| item.name.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >= 0)
result=true;

return result;
}
]]>
</mx:Script>


   <!-- Data (use ArrayCollection) -->
   <mx:ArrayCollection id="empData" source="{pb.getPhoneBook.lastResult}" />
   <!-- End Data (use ArrayCollection) -->


<!-- UI -->
<mx:HBox width="100%">
<mx:Label text="Filter:" />
<mx:TextInput id="txtFilter" width="100%" change="empData.refresh()" />
</mx:HBox>


   <mx:DataGrid id="employeeView" dataProvider="{empData}"
      initialize="pb.getPhoneBook()" height="100%" width="100%">
      <mx:columns>         
            <mx:DataGridColumn dataField="fname" headerText="First Name" />
            <mx:DataGridColumn dataField="lname" headerText="Last Name" />
            <mx:DataGridColumn dataField="org" headerText="Organization" />
            <mx:DataGridColumn dataField="telephone1" headerText="Telephone" />
      </mx:columns>
   </mx:DataGrid>

</mx:Application>


A Flex newbie
Daniel
# Posted By Daniel | 9/27/06 10:00 AM
FYI,

I got this working after some hard work. Thanks for all the great examples above. I would like to ask how to get a combo box to filter rather then a text field. Here is my current working code. I would like to change Organization into a combo box.


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="vertical" creationComplete="initApp()">



   <mx:Script>
    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.events.ListEvent;
    import mx.utils.ObjectUtil;
    [Bindable]
    public var empArray:ArrayCollection;
]]>
</mx:Script>
   
<mx:Script>
<![CDATA[

      // On startup get the data from pb
      public function initApp():void
       {
            pb.getPhoneBook();
       }

      // Cast a variable called empArray to hold the ArrayCollection
      private function getPhoneBookResult(event:Object):void
      {
         empArray = event.result as ArrayCollection;
         empArray.filterFunction=processFilter;
         empArray.refresh();
      }
      
    // Filter function for search fields
    public function processFilter(item:Object):Boolean
         {
       var result:Boolean=false;
      
       // If no filter text, or a match, then true
       if (!item.lname.length
             || item.lname.toUpperCase().indexOf(lNameFilter.text.toUpperCase()) >= 0)
             
            
          // If no filter text, or a match, then true
       if (!item.fname.length
             || item.fname.toUpperCase().indexOf(fNameFilter.text.toUpperCase()) >= 0)
             
          // If no filter text, or a match, then true
       if (!item.org.length
             || item.org.toUpperCase().indexOf(orgFilter.text.toUpperCase()) >= 0)
   
       result=true;
            return result;
         }
   
    public function showFault(fault:mx.rpc.Fault):void
    {
    mx.controls.Alert.show(fault.faultString +' '+ fault.faultDetail, 'Fault Alert Box', mx.controls.Alert.OK);
    }

]]>
</mx:Script>


   <!-- This tag calls the java class phonebook which is aliased in the remoting-config.xml file.
         It is set to an id of pb to be referenced in this app.-->
   <mx:RemoteObject id="pb" destination="phonebook" showBusyCursor="true">
      <mx:method name="getPhoneBook" fault="showFault(event.fault)" result="getPhoneBookResult(event)" />
   </mx:RemoteObject>
   <!-- End java class call tag -->


<!-- UI -->
   <mx:HBox width="100%">
      <mx:Label text="Last Name:" />
      <mx:TextInput id="lNameFilter" width="100%" change="empArray.refresh()" />
      
      <mx:Label text="First Name:" />
      <mx:TextInput id="fNameFilter" width="100%" change="empArray.refresh()" />
      
      <mx:Label text="Organization:" />
      <mx:TextInput id="orgFilter" width="100%" change="empArray.refresh()" />
   </mx:HBox>

   <mx:DataGrid id="employeeView" dataProvider="{empArray}" height="100%" width="100%">
      <mx:columns>         
            <mx:DataGridColumn dataField="fname" headerText="First Name" />
            <mx:DataGridColumn dataField="lname" headerText="Last Name" />
            <mx:DataGridColumn dataField="org" headerText="Organization" />
            <mx:DataGridColumn dataField="telephone1" headerText="Telephone" />
      </mx:columns>
   </mx:DataGrid>

</mx:Application>


Thanks
Daniel
A Flex Newbie
# Posted By Daniel | 9/27/06 4:18 PM
I am getting problen in assigning a value to Datafiels from the Query result from another Table.
I have two Lists
1.Teams
2.Team Member
I want to create a webpart which display the Team neme colomn from teams list and Who is the team leader for that particular team from Team Member list as another Colomn called Team Leader.
PLease give me the solution for this
Regards
sridebi
# Posted By sridebik | 11/22/06 11:36 PM
Just wanted to say thank you. This was a big help.
# Posted By Thomary | 1/10/07 10:36 AM
I'm having some trouble with a filter. I want to filter my DataGrid using a ComboBox. This works fine when I populate the ComboBox outside of the script block but when I populate from inside the script block (below) the filter doesn't work. I want to populate dynamically because I want the combo boxes to change depending on a previously selected comboBox.

in script block (there are several 'joint' arrays and 1 'type' array):

//type comboBox
private var TYPE:Array=
[{label:"All", data:"all"},
{label:"Stretching", data:"stretching"},
{label:"Strengthening", data:"strengthening"},
{label:"Mobilising", data:"mobilising"},
{label:"Stabilising", data:"stabilising"},
{label:"Other", data:"other"}];

//JOINT ComboBox Data
private var UPPER_LIMB:Array=
[{label:"All", data:"all"},
{label:"Shoulder/Scapula", data:"shoudler scapula"},
{label:"Elbow", data:"elbow"},
{label:"Wrist", data:"wrist"},
{label:"Hand", data:"hand"},
{label:"Fingers", data:"fingers"}];

public function filterKeyword(item:Object):Boolean{
var result:Boolean=false;
if ((jointCat.selectedLabel.toUpperCase() == "All" || item.joint.toUpperCase() ==
jointCat.selectedLabel.toUpperCase()) && (typeCat.selectedLabel == "All" ||
item.exType == typeCat.selectedLabel) && (txtFilter.length == 0 ||
item.exKeywords.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >=0 )){
result=true;
}
return result;
sortName();
}

The comboBoxes have ids 'jointCat' and 'typeCat'. I have tried jointCat.selectedItem.label and jointCat.selectedItem.data. Neither work.

However, I have found that the filter works is I select an option from one ComboBox and then click a dataGrid column heading which just displays a selected dataGrid item.

private function exDataGridClick():void{
if (exDataGrid.selectedItem){
this.currentState='exSelected';
}
}

Is there something simple I'm missing or do I just need a good nights sleep?
Thanks for any help,
Ben.
# Posted By Ben Potter | 3/29/07 6:11 AM
One other thing - the text filter works fine. It's just the comboBox filter that doesn't.
Ben.
# Posted By Ben Potter | 3/29/07 6:15 AM
Hi all,

I look at all the posts and sample above and still can't get my to work correctly. I know some where hee you need to create or use arraycollection. But I am just not get where with it. Please help review my scripts and point out what I did wrong.

Here are the script:

<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"; xmlns="*"
   xmlns:cfComponents="com.adobe.ColdFusion.components.*"
   creationComplete="initComponent()" width="210" height="400" cornerRadius="2">

   <mx:Metadata>
      [Event(name="addItem", type="com.adobe.windowedApplication.events.SelectionEvent")]
      [Event(name="editItem", type="com.adobe.windowedApplication.events.SelectionEvent")]
   </mx:Metadata>
   <mx:Script>
      <![CDATA[
         import com.adobe.windowedApplication.managers.WindowManager;
         import mx.core.UIComponent;
         import mx.collections.ArrayCollection;
         import mx.utils.ObjectUtil;
         import mx.controls.Alert;
         import mx.rpc.events.FaultEvent;
         import mx.rpc.events.ResultEvent;
         import com.adobe.windowedApplication.events.SelectionEvent;
         private var currentIndex:int = 0;
         [Bindable]
      public var CompanyArray:ArrayCollection;

         private var _key:Object;

         [Bindable]
         public function get key():Object
         {
            return this._key;
         }
         public function set key(key:Object):void
         {
            this._key = key;
         }

         private function initComponent():void
         {
            refreshList(null);
            getCompanyResult(null);
         }

         public function refreshList(event:Event):void
         {
            this.dataManager.getMasterQuery(this.key);
         }

         private function deleteItem(key:Object):void
         {
            this.dataManager.deleteItem(key);
         }

         private function EditItem(key:Object):void
         {
            var e:SelectionEvent;
            if( key == null )
            {
               e = new SelectionEvent("addItem", key);
            }
            else
            {
               e = new SelectionEvent("editItem", key);
            }
            this.dispatchEvent(e);
         }
         /**
          * RemoteObject result and error handlers
          */
         private function server_fault(event:FaultEvent):void
         {
            // dump error message
            Alert.show( ObjectUtil.toString(event.fault) );
         }

         private function getMasterQuery_result(event:ResultEvent):void
         {
            //Alert.show( ObjectUtil.toString(event.result) );
            this.masterList.dataProvider = event.result as ArrayCollection;
            this.masterList.selectedIndex = this.currentIndex;
            if (this.masterList.selectedItem != null)
            {
               this.EditItem( this.masterList.selectedItem.CompanyID );
            }
         }

         private function deleteItem_result(event:ResultEvent):void
         {
            //Alert.show( ObjectUtil.toString(event.result) );
            refreshList(null);
         }
         
         // Filter function
         // Cast a variable called empArray to hold the ArrayCollection

      private function getCompanyResult(event:Object):void
      {
      CompanyArray = event.result as ArrayCollection;
      CompanyArray.filterFunction=processFilter;
      CompanyArray.refresh();
      }

      // Filter function for search fields
      public function processFilter(item:Object):Boolean
      {
          var result:Boolean=false;

      // If no filter text, or a match, then true
         if (!item.CompanyName.length
   || item.CompanyName.toUpperCase().indexOf(search.text.toUpperCase()) >= 0)
      result=true;

         return result;

      }
      ]]>
   </mx:Script>

   <mx:RemoteObject
      id="dataManager"
      showBusyCursor="true"
      destination="ColdFusion" source="TCI.components.cfgenerated.Companies">
      <mx:method name="getMasterQuery" result="getMasterQuery_result(event)" fault="server_fault(event)" />
      <mx:method name="deleteItem" result="deleteItem_result(event)" fault="server_fault(event)" />
      </mx:RemoteObject>
   <mx:HBox width="100%" height="24">
      
      <mx:Label text="Search:" />
      <mx:TextInput width="100%" id="search" change="CompanyArray.refresh()" />
   </mx:HBox>
   <mx:HBox width="100%" height="100%">
      <mx:DataGrid
         id="masterList"
         change="this.currentIndex=this.masterList.selectedIndex; EditItem( this.masterList.selectedItem.CompanyID)"
         width="100%" height="100%" top="0" left="0" right="0" bottom="0">
         <mx:columns>
            
            <mx:DataGridColumn dataField="CompanyName" headerText="Company Name" />
         </mx:columns>
      </mx:DataGrid>

   </mx:HBox>
# Posted By phong | 3/31/07 2:10 AM
Thanks this post is a god send. If only I coud get this working.

I have been trying to gerenrate the data in the ArrayCollection from xml bought from a httpservice.

I can't get passed this error "TypeError: Error #1034: Type Coercion failed: cannot convert mx.collections::ArrayCollection@4a39d61 to Array." I have tried all different httpservice result formats, I have tried using actionscript to make it an Array Collection but I still get a similar #1034 error.

If anyone can point me in the right direction I would very grateful.

My Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml";
layout="vertical" creationComplete="stockFeed.send()">

<mx:Script>
<![CDATA[
import mx.utils.ArrayUtil;

// On startup
public function initApp():void
{

// Set filter function
// Be careful to set filterFunction
// only after ArrayCollection has been
// populated.
myData.filterFunction=processFilter;
}

// Filter function
public function processFilter(item:Object):Boolean
{
var result:Boolean=false;

// If no filter text, or a match, then true
if (!item.code.length
|| item.code.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >= 0)
result=true;
return result;
}
]]>
</mx:Script>

<mx:HTTPService
id="stockFeed"
url="http://www.1on1wholesale.co.uk/members_area/status...;
showBusyCursor="true"
resultFormat="object"
result="initApp()"/>

<!-- Array Collection Using HTTPSERVICE Source -->
<mx:ArrayCollection id="myData" source="{stockFeed.lastResult.stockreport.products.product}"/>


<!-- Array Collection using Hard coded information -->
<!--
<mx:ArrayCollection id="myData">
<mx:source>
<mx:Object code="N0505" name="Monica Rose" status="In Stock" />
<mx:Object code="N0506" name="Randy Candice" status="In Stock" />
<mx:Object code="N0507" name="Jump Start Foot Pump" status="In Stock" />
<mx:Object code="N0508" name="Carla Doll" status="Out of Stock" />
</mx:source>
</mx:ArrayCollection>
-->


<!-- UI -->
<mx:HBox width="100%">
<mx:Label text="Filter:"/>
<mx:TextInput id="txtFilter" width="100%"
change="myData.refresh()"/>
</mx:HBox>

<!-- Tile List showing results from filtered array collection -->
<mx:TileList dataProvider="{myData}" width="100%" height="300"
columnCount="2" rowCount="2">
<mx:itemRenderer>
<mx:Component>
<mx:VBox paddingLeft="30" width="150" height="150"
horizontalScrollPolicy="off" verticalScrollPolicy="off">

<mx:Label text="{data.code}" />
<mx:Label text="{data.name}"/>
<mx:Label text="{data.status}"/>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:TileList>

<!-- Data Grid showing results from filtered array collection -->
<mx:DataGrid dataProvider="{myData}"
width="100%" height="100%">
<mx:columns>
<mx:DataGridColumn headerText="code"
dataField="code"/>
<mx:DataGridColumn headerText="name"
dataField="name"/>
<mx:DataGridColumn headerText="status"
dataField="status"/>
</mx:columns>
</mx:DataGrid>

<!-- Datagrid showing results without filtering -->
<mx:DataGrid dataProvider="{stockFeed.lastResult.stockreport.products.product}" id="testing"/>
</mx:Application>
# Posted By BennyP | 3/31/07 5:43 AM
I am trying to filter this datagrid in all 3 columns whether the user inputs either name, price, or brand with the data being called through an HTTPService. I only understand how to filter one column. Please someone help me. Here is my code:

Thanks
Sal

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="vertical" creationComplete="catalogService.send()" viewSourceURL="srcview/index.html">

<mx:Script>
<![CDATA[
private function filterProduct(item:Object):Boolean{
   return item.name.match(new RegExp("^" + brandText.text, "i"));
}
]]>
</mx:Script>

<mx:HTTPService id="catalogService" url="data/catalog.xml"
resultFormat="e4x" result="(catalogService.lastResult.catalog.product)"/>

<mx:XMLListCollection id="xlc"
source="{catalogService.lastResult.*}"
filterFunction="filterProduct" />

<mx:Panel title="Product Catalog" width="380" height="385">

<mx:DataGrid dataProvider="{xlc}">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="price" headerText="Price"/>
<mx:DataGridColumn dataField="brand" headerText="Brand"/>
</mx:columns>
</mx:DataGrid>

<mx:ControlBar>
<mx:Label text="Brand" />
<mx:TextInput id="brandText" width="75"
change="xlc.refresh()" />
</mx:ControlBar>
</mx:Panel>
# Posted By Sal | 5/3/07 11:07 AM
I have a filter:

public function processFilter(item:Object):Boolean
{
   var result:Boolean=false;
   var pattern:RegExp = new RegExp("^"+txtFilter.text,"i");
   if(!item[String(columnfilter.selectedItem.data)].length
   || item[String(columnfilter.selectedItem.data)].match(pattern))
      result=true;
   return result;
}

It works perfect in using a textinput with combobox that selects the column to filter on!
I want to add another combobox that goes to a fixed field.

[Bindable]
public var theRegion: Array = [ {label:"State", data:1}, {label:"N", data:2}, {label:"S", data:3} ];

then I have the filters like this:
<mx:TextInput width="75" id="txtFilter" change="myData.refresh()" text="{brandfilter.selectedItem.data}" />
<mx:ComboBox id="columnfilter" dataProvider="{myfilter}" width="125"
close="selectedItem=ComboBox(event.target).selectedItem" change="myData.refresh();onChange(event)" />
<mx:ComboBox dataProvider="{theRegion}" width="75"
close="selectedItem=ComboBox(event.target).selectedItem" change="myData.refresh()"/>

The fixed field in the datagrid is SLMNSD and has data like: S100, S200, N543, S10, N545
so I want to do a pattern match (because in just going against the S or N. I have tried a bunch of stuff but cant seem to figure out what to put in the filter. Im thinking like this but no go!

public function processFilter(item:Object):Boolean
{
   var result:Boolean=false;
   var pattern:RegExp = new RegExp("^"+txtFilter.text,"i");
   if(!item[String(columnfilter.selectedItem.data)].length
   || item[String(columnfilter.selectedItem.data)].match(pattern) &&
   (theRegion.selectedItem.label == " State" || item[String(SLMNSD.selectedItem.label)].match(pattern))
   )
      result=true;
   return result;
}

I dont get compile errors but I get an error when selecting anything.

CAN ANYONE HELP? THANKS
George
# Posted By George Smith | 5/14/07 5:26 PM
Never mind I figured it out. I did this:
public function processFilter(item:Object):Boolean
{
   var result:Boolean=false;
   var pattern:RegExp = new RegExp("^"+txtFilter.text,"i");
   if(!item[String(columnfilter.selectedItem.data)].length
   || item[String(columnfilter.selectedItem.data)].match(pattern) &&
   (aRegion.selectedItem.data == "1" || item.Region == aRegion.selectedItem.data)
   )
   {
      result=true;
   }
   return result;
}

Just a note: Flex 2 and Ben - you rock!
# Posted By George Smith | 5/21/07 2:10 PM
Hi Ben,

I've looked at all the posts, and tried every solution that's been posted yet, i can't get this to work. Everything seems to work OK, until I type something in then I get the following error:

TypeError: Error #1010: A term is undefined and has no properties.

Here's my code:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"; xmlns="*"
   xmlns:cfComponents="com.adobe.ColdFusion.components.*"
   creationComplete="initComponent()" >

   <mx:Metadata>
      [Event(name="addItem", type="com.adobe.windowedApplication.events.SelectionEvent")]
      [Event(name="editItem", type="com.adobe.windowedApplication.events.SelectionEvent")]
   </mx:Metadata>
   <mx:Script>
      <![CDATA[
         import com.adobe.windowedApplication.managers.WindowManager;
         import mx.core.UIComponent;
         import mx.collections.ArrayCollection;
         import mx.utils.ObjectUtil;
         import mx.controls.Alert;
         import mx.rpc.events.FaultEvent;
         import mx.rpc.events.ResultEvent;
         import com.adobe.windowedApplication.events.SelectionEvent;
         import mx.utils.ArrayUtil;

         private var currentIndex:int = 0;

         private var _key:Object;

         [Bindable]
         public var gridData:ArrayCollection;
         
         [Bindable]
         public function get key():Object
         {
            return this._key;
         }
         public function set key(key:Object):void
         {
            this._key = key;
         }

         private function initComponent():void
         {
            refreshList(null);
         }

         public function refreshList(event:Event):void
         {
            this.dataManager.getMasterQuery(this.key);
         }

         private function deleteItem(key:Object):void
         {
            this.dataManager.deleteItem(key);
         }

         private function EditItem(key:Object):void
         {
            var e:SelectionEvent;
            if( key == null )
            {
               e = new SelectionEvent("addItem", key);
            }
            else
            {
               e = new SelectionEvent("editItem", key);
            }
            this.dispatchEvent(e);
         }
         /**
          * RemoteObject result and error handlers
          */
         private function server_fault(event:FaultEvent):void
         {
            // dump error message
            Alert.show( ObjectUtil.toString(event.fault) );
         }

         private function getMasterQuery_result(event:ResultEvent):void
         {
            //Alert.show( ObjectUtil.toString(event.result) );
            gridData = event.result as ArrayCollection;
            
            
            
            
            this.masterList.dataProvider = gridData;
            
            this.gridData.refresh();
            this.gridData.filterFunction = processFilter;
            this.masterList.selectedIndex = this.currentIndex;
         
            if (this.masterList.selectedItem != null)
            {
               this.EditItem( this.masterList.selectedItem.clientID );
            
               
            }
         }

         private function deleteItem_result(event:ResultEvent):void
         {
            //Alert.show( ObjectUtil.toString(event.result) );
            refreshList(null);
         }
         
         

// On startup
public function initApp():void
{

// Set filter function // Be careful to set filterFunction // only after ArrayCollection has been // populated.
//masterList.filterFunction=processFilter;

}

// Filter function
public function processFilter(item:Object):Boolean
{
var result:Boolean=false;

// If no filter text, or a match, then true
if (!item.name.length
|| item.name.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >= 0)
result=true;

return result;
}
      ]]>
   </mx:Script>

   <mx:RemoteObject
      id="dataManager"
      showBusyCursor="true"
      destination="ColdFusion" source="test2.components.cfgenerated.Client">
      <mx:method name="getMasterQuery" result="getMasterQuery_result(event)" fault="server_fault(event)" />
      <mx:method name="deleteItem" result="deleteItem_result(event)" fault="server_fault(event)" />
   </mx:RemoteObject>

   <mx:HBox id="addEditDeleteToolbar">
      <mx:Spacer width="100%"/>
      <mx:Button id="addBtn"
         icon="@Embed(source='../../../../images/add.png')" width="40"
         click="EditItem( null );" />
      <mx:Button id="deleteBtn"
         icon="@Embed(source='../../../../images/delete.png')" width="40"
         enabled="{this.masterList.selectedIndex>=0}"
         click="this.deleteItem(this.masterList.selectedItem.clientID)" />
   </mx:HBox>

   <mx:HBox width="100%" height="100%">
      <mx:DataGrid
         id="masterList"
         change="this.currentIndex=this.masterList.selectedIndex; EditItem( this.masterList.selectedItem.clientID)"
         width="100%" height="100%" top="0" left="0" right="0" bottom="0">
         <mx:columns>
            <mx:DataGridColumn dataField="client_name" headerText="Client Name" />
         </mx:columns>
      </mx:DataGrid>

   </mx:HBox>
   <mx:Label text="Search:"/>
<mx:TextInput id="txtFilter" width="100%" change="this.gridData.refresh()"/>

</mx:VBox>


Thanks for the help. I've tried all properties pertaining to your snippet of code with and without the this property (this.)
# Posted By juan | 6/27/07 6:21 PM
Hi,

I am trying to accomplish a similar effect but in Flash and using the Data Set, List Box and Input Text components. I have the XML Connector working properly and it send all of the data to the Data Set. The List component then lists all of the names.

I can make the Input Text component filter the Data Set, and therfore the List Box, but it doesnt update as I am typing like the one you created. All it does is filter the Data Set but only if I enter in the name exactly as it appears in the list.

Is it possible to accomplish this in Flash by manipulating the code you are using in Flex?


I apologize if this is a Flex only group but I have not been able to find help for this on the actionscript and flash sites I have checked.
# Posted By Ayo | 7/10/07 12:04 AM
Hi, I am trying to get this to work with data passed in by an HTTPService. It doesn't seem to work at all. Any suggestions?
# Posted By Bob | 7/16/07 7:40 PM
Never mind, I got it. The problem was figuring out what elements of the Combo Box and the data to call.

So, with a ComboBox that has an id of "tdEvent" and sorts on the datafield "AMAC," once I changed the line in Ben's example from:

if (!item.name.length
|| item.name.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >= 0)

to this:

if (tdEvent.selectedLabel == item.AMAC)

it worked great. I hope that is helpful to other ComboBox jockeys, since i just spent almost a day and a half learning all about data filtering and getting my datagrid to filter from a ComboBox. Emjoy!
# Posted By Bob | 7/16/07 8:43 PM
i have a problem filtering an array collection.

the problem occurs when i filter for a string such as 'model 1'. my array collection has model 1, model 2 ....etc ..... model 11, model 12 .......

if i filter by model 1 then it also returns model 11, model 12 etc. how can i specify that i only want a filter on 'model 1'. i had the same problems with numbers as well when i filtered looking for something with a code 10 but it returned anything with 10 in the code.

my filter currently is

private function filterModel(item:Object):Boolean
{
var isMatch:Boolean = false
if(item.Company.indexOf(modelChosen) >= 0)
{
isMatch = true
}
return isMatch;
}
# Posted By toomcfly | 8/20/07 7:07 AM
Thanks a ton. This really simplified things for me!
- Ken
# Posted By Ken Korth | 9/12/07 6:11 PM
Hi there,

first of all thx to Ben for this nice example.
Works fine.. but when i use the component I can't use the dataGrid's internal sort function anymore (the one that occurs when u click on a header). I reckon it's because the filterFunction gets called instead of or at least "distracts" the sortFunction to work properly.

Any ideas how to get rid of that?!

Cheers, Max
# Posted By Max | 11/12/07 7:59 AM
Hello Everyone! I am trying to use the filterFunction on a Tree. Is this doable?

Thanks!

-ACC
# Posted By Adolfo | 9/16/08 1:45 PM
Thanks for this code Ben. I've got it working, except...like many others....it won't work with 2 main problems:

1) If there is an empty space in the XML that is being filtered, it throws a Error #1009: Cannot access a property or method of a null object reference.
This is because it breaks the return result. Any idea's on fixing it? I tried with:
else if (!item.email1 == 0)
{
   result=true
}
No luck!

2) Cannot filter numbers!

Do you have any solutions or can anyone help me out please?
Thanks,
Pete
# Posted By Pete | 1/12/09 1:42 PM

  © Copyright 1997-2009 Ben Forta, All Rights Reserved