Пользовательский Flex ComboBox, который фильтрует поставщика данных на основе пользовательского ввода - PullRequest
3 голосов
/ 20 мая 2011

У меня есть ComboBox, и поставщиком данных является ArrayCollection трех значений: CA - Калифорния, NY - Нью-Йорк, TX - Техас.С поведением по умолчанию, когда я начинаю печатать в ComboBox, он пытается сопоставить значение с начала строки, поэтому, если я начну печатать TX, это вызовет TX - Техас.

Я хочу иметь возможностьискать в любой части строки, а не только в начале, поэтому, если я наберу «xas», она отфильтрует выбор и покажет только TX - Texas.На форумах Adobe есть очень полезный пост здесь о том, как это сделать, изменив функцию фильтра в ArrayCollection, которая предоставляет данные для ComboBox, и я адаптировал их, но у меня возникла небольшая проблема с этим.

Если пользователь выбирает значение, а затем пытается ввести в новый текст, первая буква, введенная в ComboBox, не отображается.

1) Выберите значение CA - California в ComboBox
2) Выделите текст и нажмите «n» на клавиатуре
3) Можно ожидать, что текстовое поле будет заполнено «n», но текстовое поле останется пустым

Что может бытьвызывая эту проблему?Это происходит, только если у вас уже выбрано значение.Если вы начинаете с пустого ComboBox, он работает как положено.

<fx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;
        import mx.events.FlexEvent;

        import spark.events.TextOperationEvent;

        [Bindable]
        public var arrC:ArrayCollection = new ArrayCollection([{label:'CA - California'},{label:'NY - New York'},{label:'TX - Texas'}]);

        private function changeHandler(e:*):void
        {
            if (arrC.filterFunction != doFilter)
                arrC.filterFunction = doFilter;
            arrC.refresh();
        }

        private function doFilter(item:Object):Boolean
        {
            if(String(item.label).toLowerCase().indexOf(cb.textInput.text.slice(0 ,cb.textInput.selectionAnchorPosition).toLowerCase())>-1)             
            {
                return true;
            }
            return false;
        }                       

        protected function application1_creationCompleteHandler(event:FlexEvent):void
        {
            cb.textInput.addEventListener(TextOperationEvent.CHANGE,changeHandler );
        }

    ]]>
</fx:Script>

<s:ComboBox id="cb" dataProvider="{arrC}"/>

1 Ответ

7 голосов
/ 12 июля 2012

Получил решение для вашей проблемы (потому что мне пришлось разработать собственный компонент, ведущий себя так же, как поле ввода поиска в Google).Кажется, что нормальная обработка ввода происходит неправильно, фильтруя поставщика данных.Однако я не исследовал источники неожиданного поведения настолько глубоко, насколько это было необходимо для точного объяснения вызывающей проблемы (идея возможного решения пришла слишком быстро;.)).Вот оно:

<?xml version="1.0" encoding="utf-8"?>
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx"
        skinClass="CGoogleComboSkin">
<fx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;
        import mx.collections.IList;

        import spark.events.TextOperationEvent;

        private var unfilteredDataProvider : IList;
        override public function set dataProvider(value:IList):void {
            super.dataProvider = value;

            unfilteredDataProvider = value;
        }

        override protected function textInput_changeHandler(
                event:TextOperationEvent):void {
            super.textInput_changeHandler(event);

            if (unfilteredDataProvider is ArrayCollection) {
                ArrayCollection(unfilteredDataProvider).filterFunction = filterMatches;
                ArrayCollection(unfilteredDataProvider).refresh();

                super.dataProvider = new ArrayCollection(unfilteredDataProvider.toArray()); 
            }
        }

        protected function filterMatches(item:Object):Boolean {
            if (item is String) {
                if(String(item).toLowerCase().indexOf(
                    textInput.text.slice(0,
                        textInput.selectionAnchorPosition).toLowerCase())>-1)
                    return true;
            }
            else if (labelField && labelField!= "") {
                if(item.hasOwnProperty(labelField) && 
                        String(item[labelField]).toLowerCase().indexOf(
                        textInput.text.slice(0,
                        textInput.selectionAnchorPosition).toLowerCase())>-1)
                    return true;
            }

            return false;
        }
    ]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>

Идея этого решения состояла в том, чтобы создать пользовательский Combobox путем наследования и переопределения установщика поставщика данных таким образом, чтобы нефильтрованный поставщик данных был неизменным источником.любой текстовой операцией, но пусть комбобокс flex по-своему обрабатывает коллекцию, к которой не прикреплен фильтр (который по любому входу уже является результатом фильтрации исходной коллекции).Это была просто попытка, но она сработала и применима настолько быстро, насколько я ее оценил;)

счастливое кодирование

...