Flex AutoComplete: Latest version

First off, I just wanted to thank everyone for their comments and support. It’s really nice to know that the component is being used in other people’s applications.

If you’ve come directly to this page I’d recommend checking out the post for the original version for more info on using the component.

Latest version

Here’s what’s new:

  • Fixed minor bugs: I’ve gone through all the comments/emails I received and have made sure any issues found have been resolved.
  • Icon to clear text: Now when there’s text in the chooser and the mouse is over the component a little icon appears to clear the text (ala Mac OS X).
  • Added matched part underlining: The default dropDownLabel function now shows that matched part of the text with an underline (ala Firefox 3).
  • Changed property name: Initially I went with “chosenItems” rather than “selectedItems” (b/c the component is called The Chooser). I’ve decided it’d be better to follow convention so I’ve changed any references to “chosen” to “selected” (sorry for the refactoring this will require).
  • Added a matchType parameter: There are 3 choices: match beginning, word or anyPart. “beginning” matches, as the name implies, the beginning of the string. “word” matches the beginning of any word in the string. “anyPart” matches any part of the string. I’ve added this to the demo to hopefully make this a bit clearer.

Thanks again for all the feedback

Best,
Hillel

73 thoughts on “Flex AutoComplete: Latest version”

  1. Hi Hillel,

    This is by far the best auto-complete control I have found, both in terms of features and quality … kudos for a fantastic job!

    A couple of suggestions:

    1. Add [Bindable(event=”change”)] above the setter for selectedItem and selectedItems in order to make those properties bindable, as they are in a regular ComboBox control. (Well, technically they’re bindable already as you’re dispatching change events however FlexBuilder doesn’t know that so you get a bunch of annoying compiler warnings without this change).

    2. Add an editable option. That is, allow the user to enter values not in the dataProvider (editable=”true”) or restrict entry to items in the dataProvider (editable=”false”). I need the latter in my current application and accomplished that by adding a focusOut handler as follows:

    private function handleFocusOut( event:FocusEvent ):void
    {
    var currentLabel : String = selectedItem ? labelFunction( selectedItem ) : null;
    var currentText : String = text;

    if ( currentLabel != currentText )
    {
    selectedItem = null;
    dispatchEvent( new Event( Event.CHANGE ) );
    }
    }

    Once again, many thanks for a fantastic control.

    Kind regards,

    Dave Bonnell

  2. One more suggestion:

    public function get selectedLabel() : String
    {
    return ( selectedItem == null ) ? null : labelFunction( selectedItem );
    }

    1. Dave,

      Thanks so much for the suggestions, they’re all right on point. I’ll incorporate them all into the next release.

      Best,
      Hillel

  3. Hi Hillel

    I definitely love this component (the best) and your name (my son’s one too :)).

    Everything worked fine until I changed font height : using Arial 24, autocompleted names are not visible…

    I’ll try to dig into your code to get a temporary hack, but if you can check it by yourself, it would be surely better.

    Thanks a lot for this work
    David

    1. David,

      Are the names not visible at all or do you only see the tops of the words. I think the issue may be that I’m not adjusting the row height for the drop down list component if the font is bigger. If this is the case a quick fix would be set the rowHeight property for the drop down by adding the following line of code to Combo.mxml on line 72.

      _dropDown.rowHeight = 60; (or some height big enough to fit your text)

      You also may want to change the width of the drop down to fit the text. It currently gets set on line 303 of the same file to match the width of the TextInput.

      I’ll implement a real fix in the next version of the component

      Please let me know if this resolves your issue,
      Hillel

  4. Hi Hillel, thanks for your quick answer.

    Indeed I just saw tops of the words.
    So I added this line in combo.mxml as you mention :

    _dropDown.rowHeight = promptTextInput.height;

    to make it more generic and it works great now. Thanks a lot !

    Note : I’ve tried to have the width of the dropdown different from textinput’s one, it’s ugly so I let the default parameter. IMHO you don’t need to make it configurable…

  5. Sorry to bother you again :

    Whatif I want to type data that is not in the list and read this value ?
    For the moment, I use change event to pass “this.selectedItem.name” but how can I pass not-in-list value, using change event too ?

    (note : change event is not fired when I use enter key on a not-in-list value)

    thanks for your time
    David

    1. This is a use case I’d like to improve in the next version, I’ve received a number of questions/comments related to selecting an item which isn’t in the dataProvider. For now, your best bet is to add the change event listener to the textInput component. Here’s how you’d do it (this is assuming you’ve given the chooser component an id of “chooser”)

      chooser.combo.promptTextInput.addEventListener( Event.CHANGE, handleTextChange );

      Hope this works for you,
      Hillel

    1. O dropDownWidth está definido para corresponder à TextInput largura na linha 303 do Combo.mxml. Para alterá-lo, você poderá modificar essa linha.

      Esperança essa tradução está ok,
      Hillel

  6. Hi Hillel

    (si tu parles toutes les langues, je continue en français – if you speak all languages, I continue in french :))

    The change event is not correct in that case, because it is fired each time I press a key, even when I type something which is in the list.
    I’ve added a KeyboardEvent listener instead, to fire on enter key only. But event is still fired when I press Enter, for an in-list data. And obviously this doesn’t work if I use mouse…

    I’ll wait for your next version unless I have time to find it on my own into your code.

    Thanks again.

  7. Just to let you know.
    This is how I handled it, using Enter key only for the moment :

    when the word is in the list and I press Enter key, the value of chooser.combo.promptTextInput.text is empty.
    when the word is NOT in the list and I press Enter key, the precedent variable is equal to the word.

    It’s now easy to make a difference between both cases.

    I think this is not the best way to do it (you maybe want to make it generic) but it’s a good workaround to me.

    1. Thanks for the update. As mentioned previously, I plan to improve this aspect of the component in the next release. I’m aiming for a two month release cycle so the next version should be out by the end of February. I’ll follow up with you before I implement this feature to make sure it covers your needs.

      Best,
      Hillel

  8. Can I send the amendment do? In line 303 changes, but if the list has to be greater than the textinput? I made this implementation is simple but can help others.
    How can I send?

    By Google Translate

  9. Problem using “selectedItem” as bindable. Error on line 264, the void is not prettyName returns a string. Resolution put before the 260 line:

    if (prettyName == null)
    prettyName = “”;

    by google translate.

  10. Hillel,

    I’m trying to use your autocomplete with a data provider that changes on every key input so I can get the completions from a database, but it doesn’t seem to work if the data provider changes. Am I doing something wrong or was it not designed to work that way?

    Thanks!
    Ben

    1. There was an issue in the 0.9 version of the code which prevented the autocomplete from updating when the dataprovider changed, this has been fixed in the 0.91 version. If you’re already using the latest version if you’d like you can send me your code and I’ll look through it see if I can figure out why it isn’t working.

      Best,
      Hillel

  11. Hi Hillel,

    Just wanted to says thanks for sharing your wonderful work with the community. I’ve been looking at creating a more simplified version of an autocomplete textinput which allows for searching in multiple entries differentiated by a delimiter as well as adding new entries to the dataprovider. And your AutoComplete has been a great reference/help.

    Thanks,
    Jo

  12. Hi,

    I have to agree with the other people here. This combo box rocks! One interesting thing I’ve ntoiced is that if you click the clear button (grey circle X) it doesn’t trigger a change event. Another closely related problem is if you highlight all the text and start typing something else. The first letter you type will clear the selection but it will also lose that first letter. I’m still learning flex and I’m unsure of what could be causing this problem or what the solution is.

    Thanks,
    Curtis Barrett

    1. Curtis,

      Great points. I’m just wrapping up the next version of the component and I seemed to have fixed the issue where clicking the clear button doesn’t trigger a change event. Losing the first letter when the text is selected still seems to be a problem though, I’ll try to get that resolved in the next release.

      Thanks for your feedback,
      Hillel

  13. Hillel,

    Just another happy user of your fantastic component! I’m finding that it’s these kinds of leave-no-stone-unturned enhancements of the core selection actions that really make a Flex UI come alive, and your efforts are much appreciated.

    In approach, it reminds of the elegant fusing of the popUpButton/titelBar/checkBox, a-la http://blog.flexexamples.com/2008/04/13/creating-a-pop-up-titlewindow-using-the-popupbutton-control-in-flex/ : simple, intuitive and powerful.

    cheers,
    -Ped

  14. hello ,

    nice work,,but i have problem the combo box of selection match anywhere.match word match begining is not coming …please help

    1. Vinit

      If you email me some sample code showing how you’re using the component I’d be happy to check it over.

      Thanks,
      Hillel

  15. Hello Mr Hillel,

    It’s very good to see your Chooser ^^!

    Another problem is your component doesn’t support multilangues, e.g. the label of the Browser button…

    Pls add it in your new version ^^!

    Thanks,
    Linhvu

  16. Hillel,

    Another comment ^^

    Maybe your component should support an attribute for only sellecting the data in dataProvider (like comboBox…), not another. I think it’s useful sometimes, some cases…

    Linhvu

    1. Linhvu

      Multi-language support is a good idea, it should be real easy to add. To ensure the user selects an item from the dataProvider I use a Validator, here’s an example

      Thanks,
      Hillel

  17. One odd thing I’ve noticed just now is that the selectedItem is not being bound properly. I added [Bindable] to the get selectedItem() function.
    Here’s an example:

    In your sample code add a text input box like this somewhere you can see it. I added it at line 50 right after the

    Now run the program and watch the input as you select items. Nothing happens…. Now for the really interesting part. Add the following at line 30.

    chooser.selectedItem = null;

    Now the hex code shows up when you select a color…. weird isn’t it?

    One final note: I had to modify Chooser.mxml and add [Bindable] at line 573 to make selectedItem work. Sadly I still lack the experience to know why this is happening or I’d love to help. Hopefully this helps you a bit.

  18. *Smacks Forehead* I didn’t even think that adding an something like mx:HBox (with the opening and closing brackets) would cause problems for me. Let me try again :P.

    In your sample code add a text input box like this somewhere you can see it. I added it at line 50 right after the mx:HBox
    mx:TextInput text=”{chooser.selectedItem.hex}”

    Now run the program and watch the input as you select items. Nothing happens…. Now for the really interesting part. Add the following at line 30.

    chooser.selectedItem = null;

    Now the hex code shows up when you select a color…. weird isn’t it?

    One final note: I had to modify Chooser.mxml and add [Bindable] at line 573 to make selectedItem work. Sadly I still lack the experience to know why this is happening or I’d love to help. Hopefully this helps you a bit.

  19. how do I check if an item is selected and how do you remove the selected item?

    thanks…

    Eduardo Quinhone

    1. The component fires a change event when an item is selected (or deselected). You can get the selected item by referencing the selectedItem property and remove the selected item by setting the selectedItem property to null.

  20. A quick workaround for those running into the .selectedItem not being useable with bindings. The change event does get triggered properly so create a temporary variable and bind on that instead. Then inside your change function assign that variable the value you need.

    So for the color example add this at the beginning of the scripts
    [Bindable]
    private var hex:String;

    Then add this inside handleChange();
    hex = chooser.selectedItem.hex;

    Now you are free to bind hex to any element you need and the update will be passed to it. I don’t know if this helps you pinpoint what the problem is hillel. At least there’s a workaround for the meantime.

  21. Hello,

    I just wanted to thank you for sharing this component. I used the Adobe autocomplete component in many places in my application, which has resulted in many bugs and many hours of painful debugging. After all that time, I still could not get the Adobe version to work well. I replaced it with your component today, and all my bugs are gone!!!

    You’ve done an outstanding job on this component. Adobe should seriously consider replacing theirs with yours.

    Thank you so much.

  22. I’m trying to modify Chooser according to byalpel’s suggestion but I never see the value of combo.promptTextInput.text as empty after pressing Enter, whether I typed something not present in the list or not.

    I’ve got the KeyboardEvent listener set up and firing whenever ENTER is pressed but I just don’t see that rule to differentiate the cases.

    Anyone else implement this workaround with success?

    1. Adam,

      I’m just about to release a new version of the component and will try to incorporate this behavior. To be clear, you’d like the component to fire a change event if the user types in text and then clicks enter (regardless of whether or not the user has chosen an item from the dataProvider).

      Thanks,
      Hillel

  23. Not quite. The true aim is to know when a user has typed something not represented by any items in the dataProvider. I thought byalpel’s workaround was the only way so far devised of doing this.

    It’s basically the feature you started to address in your Jan 6 comment.

    But if the component would fire a new event, say “newValue”, when enter is pressed and the user has typed in text that is NOT in the dataProvider, that would solve my problem.

    There’s a modified version of the Adobe Autocomplete component that fires a “valueWritten” event upon each keystroke that results in a string not found among the labels of the dataProvider. That was useful but there are so many other issues with that component (especially with more than one instance) that your component so far seems a godsend.

    1. How about this…. you add a keyDown event handler to the Chooser component. When it fires, check that the key pressed is the Enter key. If the text property is set and the selectedItem property is null you know the user is entering a new value. This doesn’t work right in the current version (the first time they click enter the selectedItem property is still null) but will behave correctly in the new version. Would this work for you?

  24. Just wanted to stop in a say this is just a really well built and very functional component. Good work and Thank you.

  25. Yes, that would work and was actually one of the conditionals I tried but of course ran into that first time selection problem.

    Thanks a lot for this Hillel! When are you looking to release the new version?

  26. I might be missing something, or you may already be accounting for this in the new version, but FYI in case:

    Using version 0.91, assigning the dataProvider to an AC that has it’s own external, application-specific filterFunction does not restrict the search results to the filtered set: it continues to pull from the entire source array. The debugger verifies that the length of Chooser.dataProvider gets restricted correctly upon filtering; but all rows are still available in the search.

    My workaround was to copy ‘defaultFilterFunction’ directly into my app, assign this as the chooser’s fitlerFunction, and add a line like the following at the top:

    if (!myCustomFilterFunc(item))
    return false;

    And thanks again for sharing such a useful component.

  27. I added some code so that the drop down menu is either moved or hidden when the application is resized and the drop down is visible.

    Chooser.mxml:

    line 90: addEventListener( MoveEvent.MOVE, handleMoveEvent );

    line 135:

    private function handleMoveEvent( event:MoveEvent ):void
    {
    combo.moveDropDownMenu(); // or hideDropDownMenu()
    }

    Combo.mxml gets two new functions:

    public function hideDropDownMenu():void
    {
    if (isDropDownVisible())
    {
    hideDropDown();
    }
    }

    public function moveDropDownMenu():void
    {
    if (isDropDownVisible())
    {
    positionDropDown();
    }
    }

    I would also recommend an option to turn off the scrollbar on the List control for the drop down menu, so users can just use the up/down arrows to navigate. Great little component, thanks!

  28. Great works!

    Only one mistake for me. I need it to choose from a arrayCollection of city but i can set a default city if i already have it? for example if it is a textInput i can set in mxml

    Thank’s in advance

  29. […]Hillel Says:
    January 22, 2009 at 9:16 am

    Linhvu

    Multi-language support is a good idea, it should be real easy to add. To ensure the user selects an item from the dataProvider I use a Validator, here’s an example

    Thanks,
    Hillel
    […]

    Hi Hillel,

    Sorry, i can’t see your Validator example, pls rewrite again!

    Thanks so much,
    Linhvu

    1. Linhvu,

      Sorry about that, didn’t notice that using < and > caused problems…

      <mx:Validator id=”validator ” required=”true” source=”{ chooser }” property=”selectedItem” listener=”{ chooser .combo.promptTextInput.textInput }”/>

  30. Hi Hillel,

    thanks to share this verry good Autocompleter,

    Here are two function you could add to StringUtils class to provide the new feature of filtering Phonectically !

    (comming from : http://jobemakar.blogspot.com/2007/08/soundex-comparing-words-phonectically.html)

    // === BEGIN

    static private function run(s:String):String
    {
    var SIZE:int = 4;
    var i:int;

    var strUpper:String = s.toUpperCase();

    var charArr:Array = new Array();

    for (i=0;i<strUpper.length;++i)
    {
    charArr[i] = strUpper.charAt(i);
    }

    var firstLetter:String = charArr[0];

    // convert letters to numeric code
    for (i = 0; i < charArr.length; i++)
    {
    switch (charArr[i]) {
    case ‘B’:
    case ‘F’:
    case ‘P’:
    case ‘V’:
    charArr[i] = ‘1’;
    break;
    case ‘C’:
    case ‘G’:
    case ‘J’:
    case ‘K’:
    case ‘Q’:
    case ‘S’:
    case ‘X’:
    case ‘Z’:
    charArr[i] = ‘2’;
    break;
    case ‘D’:
    case ‘T’:
    charArr[i] = ‘3’;
    break;
    case ‘L’:
    charArr[i] = ‘4’;
    break;
    case ‘M’:
    case ‘N’:
    charArr[i] = ‘5’;
    break;
    case ‘R’:
    charArr[i] = ‘6’;
    break;
    default:
    charArr[i] = ‘0’;
    break;
    }
    }

    // remove duplicates
    var output:String = “” + firstLetter;
    var lastChar:String = charArr[0];

    for (i = 1; i < charArr.length; i++)
    {
    if (charArr[i] != ‘0’ && charArr[i] != lastChar)
    {
    lastChar = charArr[i];
    output += lastChar;
    }
    }

    // pad with 0’s or truncate
    for (i = output.length; i < SIZE; i++)
    {
    output += ‘0’;
    }
    output = output.substring(0, SIZE);

    return output;
    }

    static public function soundsLike( word1:String, word2:String ):Boolean
    {
    return (( run( word2 ) == run( word1.substr(0,word2.length) ) )?true:false);
    }

    // === END

    then the filter handler function could be :

    chooser.filterFunction = function( item:Object, searchStr:String ):Boolean
    {
    if ( StringUtils.soundsLike(item.name, searchStr) )
    {
    return true;
    }
    return false;
    });

    1. Brice,

      That’s really cool, thanks for sharing. I’d like to build it in to the next version, the only issue I’m having is figuring out how to display which part of the search string matches.

      Thanks,
      Hillel

  31. Hi Hilel,
    thank you for this component. Is it possible to customize the Panel that appears after pressing the browse Button. I don’t need all items from dataProvider in this list.

    Thank you in advanced
    Frank

    1. Frank,

      You’re in luck. I just added that feature in the latest version (0.98.1). There’s a new property called browserFields. You pass it an array of the fields to display in the browser datagrid.

    2. Wait… sorry. just re-read your comment. You want to change the items shown (not the properties). In that case one option is to extend the current Browser class and then set your new class in the browserClass property.

  32. thanks for sharing this component. i use 1.1_fx4swc version. the issue is when i create this component to dynamically using actionscript, the dropdown is not coming. if i test this in mxml with the same set of attributes it works fine. can you please help?
    –actionscript code—
    var colInput:AutoComplete = new AutoComplete();
    colInput.id=”colInputId”;
    colInput.labelField=”label”;
    colInput.matchType=”anypart”;
    colInput.prompt=”enter..”;
    colInput.allowNewValues=”false”;
    colInput.allowMultipleSelection=”true”;
    colInput.allowDuplicates=”false”;
    colInput.allowMultipleSelection=”true”;
    colInput.allowEditingNewValues=”false”;
    colInput.backspaceAction=”focus”;
    colInput.dataProvider=myarraycollection;
    colInput.width=100;
    myHbox.addElementAt(colInput, 1);

      1. Hi Hillel,

        Thanku for providing such a wonderful autocompletemodified component.
        I’m not able to prevent pasting text on the textinput.and i cannot find a textinput event in the component.

        Could you please help me out(I’m just a beginner) !!!

      2. The component is put together using a Grid but you can access the main TextInput using the following..

        autoComplete.textInput.textInput

        The first TextInput is a custom PromptTextInput component which enables using a placeholder text (and contains the actual TextInput).

  33. Hi Hillel,

    Thanks for the fast reply . I’m able to prevent pasting from clipboard now by using super.text.length >1 .But im not able to enter more characters in textinput now.Actually i want the backspace and delete to work in the same way as Escape. But all the time the first name in the data collection, of the letter i’ve entered, fills the textinput whenever i press delete or backspace. And Escape works just fine.The only change i’ve made is ..

    override protected function textInput_changeHandler(event:Event):void
    {
    super.textInput_changeHandler(event);
    //Stores the text typed by the user in a variable
    if(super.textInputeventlength>1)
    {
    text=”—Select—“;
    return;
    }
    typedText=text;

    AND IN THE FUNCTION “keyDownHandler(event:KeyboardEvent):void” i changed..

    else if((event.keyCode==Keyboard.ESCAPE||event.keyCode==Keyboard.DELETE||event.keyCode==Keyboard.BACKSPACE) && showingDropdown)
    {
    textInput.text = _typedText;
    textInput.setSelection(textInput.text.length, textInput.text.length);
    showingDropdown = false;
    dropdownClosed=true;
    }

    Thanks in advance !!!!

    1. I don’t recognize any of this code. For example, my AutoComplete component doesn’t have a function called keyDownHandler. Are you sure you’re using my component?

  34. Hi Hillel,

    Which all functions are called when i press backspace and delete ??sorry for the basic questions !!

  35. Hi Hillel,
    I have been using your autocomplete mxml. One weird thing happening with my execution is that for the first time it picks text pasted on it and does autosearch but if i deleted the text and repaste it or if i paste for second time, the change event is not fired and search is also not called.

    Detailed description:
    I am using a inputbox which extends autocomplete. There are 2 cases for which my code is failing
    1. When i load the page and paste for the first time, it triggers Event.CHANGE and calls search method. But if i paste for second time, Evnet.CHANGE is not triggered.

    2. After i paste it for the first time and delete it. While deleting event.change is triggered but search is not triggered. And after deleting if i paste again, it is neither triggering Even.CHANGE neither search.

    i need help on this

    1. I’m not able to replicate your issue in the demo. Do you see this issue if you use the AutoComplete class rather than inputbox.

  36. hi hillel,
    i want comboboxes which are interdependent and autocomplete for local language data like kannada, hindi tamil……….please provide me code and which version of flex supports combobox autocomplete facility.(mine is flex3.0).

    any bit of guidence will be highly appreciated,
    Thanks In Advance

Leave a comment