Question

I am using Adobe Flash Builder 4 Premium. I have a mx:DataGrid and a s:TextInput, and I am trying to set up a search box that filters the DataGrid on each key press.

This page shows a nearly perfect example of what I'm trying to do, except that I'm setting this up in a s:TitleWindow, which is brought up as a popup using the PopUpManager. The list I'm trying to filter can be very large. It is a list of usernames, fetched from a MySQL database via PHP. Since it can be so large, I want the list to be populated once in the main application and then referenced in the popup window so that it doesn't have to fetch all the usernames each time the user opens the popup.

I have all of this working fine for the first time you bring up the popup, but if you close it and bring it up again, I get this runtime error:

Flash runtime error

I also get this error if I attempt to set the filterFunction back to null just before closing the popup.

See sample code below:

Main Application:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx">
    <fx:Script>
        <![CDATA[
            import mx.collections.*;
            import mx.managers.PopUpManager;

            [Bindable] public var allMembersList:ArrayCollection;

            private function openPopup():void
            {
                var popupInstance:popup = PopUpManager.createPopUp(this as DisplayObject, popup, true) as popup;
                PopUpManager.centerPopUp(popupInstance);
            }
        ]]>
    </fx:Script>
    <s:Button label="Open Popup" click="openPopup()"/>
</s:Application>



Popup:

<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx"
               xmlns:model="services.model.*"
               tabChildren="false"
               close="close()">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.core.FlexGlobals;
            import mx.managers.PopUpManager;

            private function getUsers(startsWith:String = ""):void
            {
                if (FlexGlobals.topLevelApplication.allMembersList == null)
                {
                    FlexGlobals.topLevelApplication.allMembersList = new ArrayCollection();
                    getUsersResult.token = php.getUsers();
                }

                FlexGlobals.topLevelApplication.allMembersList.filterFunction = function(item:Object):Boolean
                {
                    return item.username.match(new RegExp("^"+ startsWith, "i"));
                };
                FlexGlobals.topLevelApplication.allMembersList.refresh();
                grdMemberList.dataProvider = FlexGlobals.topLevelApplication.allMembersList;
            }

            private function getUsersResultHandler():void
            {
                var users:Object = getUsersResult.lastResult;
                for each (var user:Object in users)
                    FlexGlobals.topLevelApplication.allMembersList.addItem({"username":user.username});
            }

            private function close():void
            {
                FlexGlobals.topLevelApplication.allMembersList.filterFunction = null;
                FlexGlobals.topLevelApplication.allMembersList.refresh();
                PopUpManager.removePopUp(this);
            }
        ]]>
    </fx:Script>
    <fx:Declarations>
        <model:MODEL id="php" fault="{Alert.show('There was a PHP error!\nPlease note the steps taken to produce this error and call support.\n\nError Message: '+ event.fault.faultDetail, 'Error');}" showBusyCursor="false"/>
        <s:CallResponder id="getUsersResult" result="getUsersResultHandler()"/>
    </fx:Declarations>

    <mx:DataGrid id="grdMemberList" creationComplete="getUsers()">
        <mx:columns>
            <mx:DataGridColumn headerText="Member List" dataField="username"/>
        </mx:columns>
    </mx:DataGrid>
    <s:TextInput id="txtUsername" keyUp="{ if (event.charCode != 13 && event.charCode != 0) getUsers(txtUsername.text); }"/>
</s:TitleWindow>

The app still seems to work as expected, despite the error, but I'm not a fan of having errors in my app, so I would really like to figure out what is causing this issue.

Thanks!

Was it helpful?

Solution

It turns out the problem was with the tabChildren property. The documentation says not to use this property in Flex, but to use hasFocusableChildren instead. Not sure why this problem only showed itself once I was trying to set the filterFunction.

The reason I was setting tabChildren to false was so that the default TAB key functionality (switching focus) would not take place, so that I can control that behavior myself. The hasFocusableChildren property doesn't work (or at least, setting it to false doesn't stop the TAB key from switching focus), so I may need to try another means of capturing the TAB key event and stopping it.


EDIT:

For any that are interested (even though it doesn't really have anything to do with the original post), the solution was to change:

<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               xmlns:model="services.model.*"
               width="1000"
               height="550"
               tabChildren="false"
               close="close()">

to:

<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               xmlns:model="services.model.*"
               width="1000"
               height="550"
               keyFocusChange="{ event.preventDefault(); }"
               close="close()">

OTHER TIPS

I never try testing your code (because it needs server-side also) but I think you should not set filterFunction back to null. Alternatively, you could set it to a function that always returns true.

function defaultFilterFunc( item: Object ): Boolean { return true; }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top