Blog

13Jul
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:

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

4
5    <mx:Script>
6    <![CDATA[
7
8    // On startup
9

10    public function initApp():void
11    {
12
13        // Set filter function
14
        // Be careful to set filterFunction
15
        // only after ArrayCollection has been
16
        // populated.
17

18        myData.filterFunction=processFilter;
19    }
20        
21    // Filter function
22

23    public function processFilter(item:Object):Boolean
24    {
25        var result:Boolean=false;
26
27        // If no filter text, or a match, then true
28

29        if (!item.name.length
30            || item.name.toUpperCase().indexOf(txtFilter.text.toUpperCase()) >= 0)
31            result=true;
32                
33        return result;
34    }
35    ]]>
36    </mx:Script>
37
38    <!-- Data (use ArrayCollection) -->
39    <mx:ArrayCollection id="myData">
40        <mx:source>
41            <mx:Object name="Ben Forta" location="Oak Park, MI" phone="(248)555-5555" />
42            <mx:Object name="Jane Doe" location="New York, NY" phone="(212)555-1234" />
43            <mx:Object name="Jim Jones" location="Atlanta, GA" phone="(414)555-1212" />
44            <mx:Object name="Roberta Roberts" location="Chicago, IL" phone="(312)555-4321" />
45            <mx:Object name="Steve Stevens" location="Boston, MA" phone="(617)555-5656" />
46        </mx:source>
47    </mx:ArrayCollection>
48
49    <!-- UI -->
50    <mx:HBox width="100%">
51        <mx:Label text="Filter:"/>
52        <mx:TextInput id="txtFilter" width="100%"
53                        change="myData.refresh()"/
>

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

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

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

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

64        </mx:columns>
65    </mx:DataGrid>
66    
67</mx:Application>

Related Blog Entries

Comments (46)



  • Oliver Merk

    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

  • Shigeru

    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...

    #2Posted by Shigeru | Jul 14, 2006, 03:00 PM
  • Ben Forta

    Shigeru, I'd not load 100,000 rows into a DataGrid, that is what paging is for.

    --- Ben

    #3Posted by Ben Forta | Jul 14, 2006, 03:07 PM
  • Cyril

    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 ?

    #4Posted by Cyril | Jul 17, 2006, 08:46 AM
  • Cyril

    Oups... forget it, it works perfectly ! :-) I think i really need holidays...

    #5Posted by Cyril | Jul 17, 2006, 09:07 AM
  • Mario Talavera

    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...

    #6Posted by Mario Talavera | Jul 19, 2006, 10:17 AM
  • carlosM()

    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>

    #7Posted by carlosM() | Aug 4, 2006, 05:11 PM
  • Joseph Abenhaim

    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.

    #8Posted by Joseph Abenhaim | Aug 8, 2006, 07:48 PM
  • Ben Forta

    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

    #9Posted by Ben Forta | Aug 8, 2006, 09:00 PM
  • Joseph Abenhaim

    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>

    #10Posted by Joseph Abenhaim | Aug 9, 2006, 09:47 AM
  • Steve Gustafson

    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

    #11Posted by Steve Gustafson | Aug 15, 2006, 05:24 AM
  • Russ

    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

    #12Posted by Russ | Aug 16, 2006, 03:31 PM
  • George Smith

    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

  • George

    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?

    #14Posted by George | Aug 17, 2006, 12:30 PM
  • Russ

    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

    #15Posted by Russ | Aug 17, 2006, 12:40 PM
  • Gus

    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

    #16Posted by Gus | Aug 17, 2006, 12:46 PM
  • George

    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>

    #17Posted by George | Aug 17, 2006, 12:59 PM
  • George

    Gus,
    What is the name of the remoteObject that you are using?

    #18Posted by George | Aug 17, 2006, 01:38 PM
  • George

    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

    #19Posted by George | Aug 17, 2006, 02:37 PM
  • Gus

    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>

    #20Posted by Gus | Aug 18, 2006, 07:58 AM
  • George

    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

    #21Posted by George | Aug 18, 2006, 01:26 PM
  • Rich

    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>

    #22Posted by Rich | Aug 23, 2006, 09:53 AM
  • Al Foote

    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

    #23Posted by Al Foote | Sep 1, 2006, 02:23 PM
  • Daniel

    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

    #24Posted by Daniel | Sep 27, 2006, 10:00 AM
  • Daniel

    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

    #25Posted by Daniel | Sep 27, 2006, 04:18 PM
  • sridebik

    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

    #26Posted by sridebik | Nov 22, 2006, 11:36 PM
  • Thomary

    Just wanted to say thank you. This was a big help.

    #27Posted by Thomary | Jan 10, 2007, 10:36 AM
  • Ben Potter

    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.

    #28Posted by Ben Potter | Mar 29, 2007, 06:11 AM
  • Ben Potter

    One other thing - the text filter works fine. It's just the comboBox filter that doesn't.
    Ben.

    #29Posted by Ben Potter | Mar 29, 2007, 06:15 AM
  • phong

    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>

    #30Posted by phong | Mar 31, 2007, 02:10 AM
  • BennyP

    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>

    #31Posted by BennyP | Mar 31, 2007, 05:43 AM
  • Sal

    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>

    #32Posted by Sal | May 3, 2007, 11:07 AM
  • George Smith

    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

  • George Smith

    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!

  • juan

    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.)

    #35Posted by juan | Jun 27, 2007, 06:21 PM
  • Ayo

    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.

    #36Posted by Ayo | Jul 10, 2007, 12:04 AM
  • Bob

    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?

    #37Posted by Bob | Jul 16, 2007, 07:40 PM
  • Bob

    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!

    #38Posted by Bob | Jul 16, 2007, 08:43 PM
  • toomcfly

    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;
    }

    #39Posted by toomcfly | Aug 20, 2007, 07:07 AM
  • Ken Korth

    Thanks a ton. This really simplified things for me!
    - Ken

    #40Posted by Ken Korth | Sep 12, 2007, 06:11 PM
  • Max

    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

    #41Posted by Max | Nov 12, 2007, 07:59 AM
  • Adolfo

    Hello Everyone! I am trying to use the filterFunction on a Tree. Is this doable?

    Thanks!

    -ACC

    #42Posted by Adolfo | Sep 16, 2008, 01:45 PM
  • Pete

    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

    #43Posted by Pete | Jan 12, 2009, 01:42 PM
  • Adobe Flex Tutorial

    Hey,
    i created a Flex Library (DataFilterLib) that take care of all the filtering process, completly in MXML.
    This library is free, you can find the project details there:
    http://code.google.com/p/flex-datafilterlib/
    If you want to have a look at the examples, they are all there (source available):
    http://www.flex-tutorial.fr/DataFilterLib/examples/
    Check the examples online if you want to see how to filter on multiple criterias, using different Flex UI Components (CheckBox, Slider, List, ...).

    Thanks,
    Fabien
    http://www.flex-tutorial.fr

  • Flexicious

    Check out www.flexicious.com. Its a extended DataGrid control that provides all the filter functionality and a lot more!!

  • Prasy

    Works like a charm Very nice example thanks

    #46Posted by Prasy | Aug 12, 2010, 09:09 AM