Flex AutoComplete: New batch of changes

If you’ve come straight to this post I’d recommend checking out the previous posts for this component for more info on using it.

Latest version

Here’s what’s new:

  • Ability to add new items: You can now select items which aren’t in the data provider. To enable this feature you need to set the isStrict property to false. I’ve also added an allowDuplicates flag which controls whether or not you can add an item more than once
  • Added style property: I’ve added a style property which lets you control how the selected items are displayed. There are currently 3 choices: Mac Mail, Facebook and underlined.
  • Created some documentation: It’s not great but at least it’s a start. You can find it in the zip file in the doc folder
  • A bunch of other small tweaks and bug fixes: I’ve tried to incorporate the changes suggested in comments in the blog but I’m sure I missed some things. Please let me know if you suggested a change which didn’t make it in and I’ll get it in a future release.
  • Changed component name to AutoComplete: I’ve decided that for clarity’s sake it’s better to call it AutoComplete (rather than Chooser). I’m sorry for the refactoring this will require (hopefully it should be pretty minimal)

I’ve put the codebase on Google Code. If you’re interested in getting involved in the project please let me know.

Thanks,
Hillel

Tags: ,

40 responses to “Flex AutoComplete: New batch of changes”

  1. Tracy Spratt says :

    Only hours after you post the latest code, and someone is already wanting to mocify it!

    The ‘flow” style multi-select seems to work well, and the auto height behavior will benefit many, but I want to be able to fix the height to a specific value and show a scrollbar if the content exceeds that height. I had done this with the previous version using a TextArea for the prompt input.

    I was looking at the code to see how I could do this with the current version. Hillel, what the heck is mx:ToolBar? It obviously exists, but I could not find it anywhere in the docs. Google finds it, but just a few usages, no documentation, and Flex
    Builder has no code completion for it.

    Do you have any suggestions on how to set its height? It takes the height property but seems to ignore it. Or are you adjusting its height programatically? I’m still looking.

    Tracy

  2. Tracy Spratt says :

    Ok, I can do what I need by jiggling the layout properties of the various components and containers. Now to see if I can make it an optional setting.

    • Hillel says :

      Hey Tracy,

      I hadn’t heard of the ToolBar class either, It’s part of the RichTextEditor class. It’s marked as [ExcludeClass] which is why code completion doesn’t work on it. You can find out more about it here.

      Best,
      Hillel

  3. Jmardar says :

    Man, thank you very much

  4. Ed LaFave says :

    Hey Hillel,

    Just upgraded to the new version and I’m very excited about the facebook/mac styles!

    I’m going through the process of updating your component to meet all the use cases I have. Throughout the next couple days I’ll be posting my solutions in case you or anybody else wants to use them. Here is my first issue:

    Use Case: Suppose items A, B, and C are currently select. If ItemA is removed from the data provider then the AutoComplete component should automatically remove Item A and only display Items B and C.

    Problem: When the AutoComplete component is in multiSelect mode it doesn’t handle removals from the dataProvider correctly.

    Example: If you have items A, B, C, and D selected and remove item C from the data provider then you’ll wind up with items A, B, C, and D (2x) selected.

    Why: Behind the scenes it never removes your initial selections and that is why A, B, C, and D reamins selected. It tries to add “A B D” in rapid succession. However, each time it tries to add a new item it essnetially overwrites the previous item because the commitProperties method isn’t given enough time to run.

    Solution: Inside AutoComplete::commitProperties I changed the following code block:

    if (_selectedItemsChanged && _dataProvider)
    {
    _selectedItemsChanged = false;
    _selectedItems.removeAll();
    //Ed LaFave added this. Suppose ItemA was selected and it was removed from
    //the dataProvider. The handleDataProviderChange sets the selectedItems property
    //with all of the previously selected items except ItemA. If we don’t clear the
    //FlowBox then we wind up with duplicates.
    combo.clearFlowBox();

    for each (var selectedItem:Object in _initialSelectedItems)
    {
    var foundItem:Object = null;

    for each (item in _dataProvider.source)
    {
    if (item == selectedItem)
    {
    foundItem = item;
    }
    else if (item.hasOwnProperty( _keyField ) && item[_keyField] == selectedItem[_keyField])
    {
    foundItem = item;
    }

    if (foundItem)
    {
    combo.setSelectedItem( foundItem, true );
    //Ed LaFave added this. I had to validate now because the setSelectedItem
    //method was being called multiple times in rapid succession. Each call to
    //setSelectedItem essentially overwrote the previous call because the commitProperties
    //method didn’t get to run.
    combo.validateNow();
    foundItem = true;
    break;
    }
    }

    if (foundItem == null)
    {
    combo.setSelectedItem( selectedItem, true );
    //Ed LaFave added this. I had to validate now because the setSelectedItem
    //method was being called multiple times in rapid succession. Each call to
    //setSelectedItem essentially overwrote the previous call because the commitProperties
    //method didn’t get to run.
    combo.validateNow();
    }
    }
    }

    Thanks,
    Ed LaFave

  5. Ed LaFave says :

    Hillel,

    Use Case: Suppose items A, B, and C are currently select. If ItemA is removed from the data provider then the AutoComplete component should automatically remove Item A and only display Items B and C.

    Problem: When the AutoComplete component is NOT in multiSelect mode it doesn’t remove the selected Item when it is removed from the data provider.

    Why: The Combo::commitProperties method didn’t account for the case where the selectedItem was null.

    Solution: I added the following code inside Combo::commitProperties:

    if (canBeAdded && value)
    {
    …BUNCH OF CODE HERE…
    }
    else if(_selectedItems.getItemIndex( value ) >= 0 && isNew)
    {
    …BUNCH OF CODE HERE…
    }
    else
    {
    validItem = false;

    //Ed LaFave added this. If we don’t remove the selected items
    //we’re not accounting for the case where value = null. If we
    //don’t account for this case then if the selected item is removed
    //from the data provider it continues to be displayed.
    clearFlowBox();
    _selectedItems.removeAll();
    }

    Thanks,
    Ed LaFave

  6. Ed LaFave says :

    Hillel,

    Use Case: I basically have a global ArrayCollection that is used in several places throughout my app—most notably as the dataProvider for the AutoComplete objects I use. As one might expect it is only acceptable for the contents of this ArrayCollection to change when I specifically add or remove an item from that ArrayCollection.

    Problem: I use my global ArrayCollection as the dataProvider of the AutoComplete object. As the user uses the AutoComplete widgets the contents of my global ArrayCollection change even though I haven’t added/removed items from the ArrayCollection.

    Why: The AutoComplete class shares its dataProvider with the Combo class. As the user types in the AutoComplete widget the Combo class filters the dataProvider. Since the Combo class is operating on my “global” ArrayCollection it results in changes that I haven’t explicitly made.

    Solution: In the AutoComplete::commitProperties method I create a copy of the dataProvider and use that copy for Combo’s dataprovider:

    //Ed LaFave added this. The Combo class changes the contents of the dataProvider
    //in order to filter. My dataProvider is used in several places throughout my app
    //so it isn’t appropriate for that ArrayCollection to be filtered. Therefore we’ll
    //let the Combo class operate on its own ArrayCollection object.
    var dataProviderCopy:ArrayCollection = new ArrayCollection(_dataProvider.source);
    combo.dataProvider = dataProviderCopy;

    ps: I think that is the way you originally implemented this so you must have had a good reason for changing it. Hope I didn’t break something but everything seems to work the way I want it to.

    Thanks,
    Ed LaFave

  7. Guy Djemal says :

    Hilel,

    Firstly I must admit AutoComplete is coming along nicely, it’s a very nice component.

    I’m having a slight issue with using it with a dynamic data provider. Perhaps I am doing this incorrectly but I found I had to make a few changes to get this working correctly.

    BTW to simulate a dynamic data provider just create a function to do a callLater to repopulate the dataprovider. I then bound this to Combo.SEARCH_CHANGE event and updated the data provider unless an item was selected.

    My changes as follows:
    1) In Combo.mxml at the end of function commitProperties add an extra call to handleChange(null, false).

    2) handleChange() add an extra argument called propogate. This stops the clearFlowBox() call and the extra event firing. To aid understanding see below:

    public function handleChange( event:Event, propogate:Boolean = true):void
    {
    if (selectedItem && !_isMultiSelect && propogate)
    {
    _selectedItems.removeAll();
    clearFlowBox();
    }

    sizeTextInput();

    if (!_dataProvider)
    {
    return;
    }
    _searchStr = textInput.text;

    //var start:Date = new Date();
    filterData();
    //var end:Date = new Date();
    //trace(“>> search took: ” + (end.getTime() – start.getTime()) + ” msecs” );

    if (propogate)
    {
    var event:Event = new Event( SEARCH_CHANGE );
    dispatchEvent( event );
    }

    I would be interested if others managed to use out of the box.

    Cheers,
    Guy.

  8. Matthew says :

    Hello; awesome component.

    Using isStrict=”false”, the user must press enter after entering text which does not appear in the list of options, or the value is not set on the field. Is there a way to “force set” the new text as the value of the field without the user having to remember to press enter before moving on to the next field? Perhaps this could be done when the field loses focus, or…?

    Thanks,
    Matthew

    • Hillel says :

      Mathew,

      Thanks for the feedback. Yeah, that’s a good idea… I think on “focus out” is the way to go. I’ll add it to the next version. I’ve made a lot of changes in the latest release and plan to do a mini-update in a week or two.

      Best,
      Hillel

  9. Tracy Spratt says :

    Regarding the copy dataProvider yes/no question, if we leave it like it is no, without the copy, then we can still isolate the main data source from changes by making the copy *before* assigning the dataProvder to the component.
    Tracy

  10. Stiggler says :

    Hi Hillel,

    Thanks for the hard work on this great component! You’ve incorporated a lot of new, cool features in this latest release.

    However, it seems to me it’s been a bit rushed and not tested thoroughly. For example, selectedItems seems to be fundamentally broken; it doesn’t work to select multiple items in your demo and I’m having a few other issues as well that may be symptoms of the same problem.

    Any chance you could make the earlier versions available such that users can revert to a stable version while bugs are being ironed out?

    • Hillel says :

      Stiggler,

      I’m sorry to hear you’re having trouble with the latest version. If you could explain your issues in more detail I’d be happy to help you figure it ou. To test the selectedItems property in the demo I use the following line of code.

      <mx:List dataProvider=”{ autoComplete.selectedItems }” labelField=”name”/>

      Here’s a link to the previous version http://web.me.com/hillelcoren/Site/chooser-0.93.zip

  11. Guy Djemal says :

    Hilel,

    it would also be nice if we could override the number of items to display, i.e. ROW_COUNT value in Combo.

    If items render quite large the pop up always displays to the top of the combo.

    Cheers,
    Guy.

  12. Stiggler says :

    Hillel,

    Try selecting multiple items in the demo for the latest component version; you may select several items in the browsing window, but, unlike previous versions, only one of them will actually be selected on clicking OK.

    Other bugs I’ve come across so far, exclusive to the latest version, are:

    * You can make the component display several items at once simply by setting selectedItem several times; it doesn’t appear to be cleared in-between. This works regardless of what isMultiselect is set to.

    * If you type a string longer than the width of the component, that string now continues across the right boundary of the component instead of single line wrapping.

    Hope that helps.

  13. Stiggler says :

    Additionally, AutoComplete’s selectedItem property is null when the component’s change event is fired following selecting an item in the Browse dialog.

    • Hillel says :

      Stiggler,

      Thanks very much for finding these issues. I’ve resolved all of them (although for the case where the text is too long I’ve needed to show scrollbars as it will be difficult to implement line wrapping). If you’d like to make use of these changes you check out a copy of the codebase from the Google Code site

      Thanks,
      Hillel

  14. Stiggler says :

    Nice work on getting those fixes in so quickly!

    The wrapping issue of course has to do with your use of the ToolBox (FlowBox), which I assume is used in order to display the styles you’ve incorporated. However, using those styles come with a price as the display width and height of the component are no longer enforced. In addition to breaking the right boundary on typing a long string, a selectedItem whose string length is greater than the width of the component will force the text input to display multiple lines instead of only displaying part of the item on a single line.

    Perhaps you could consider doing away with the ToolBox for a particular style that doesn’t necessarily need it (underline)? Having scrollbars in an input component isn’t desirable in a lot of cases.

    Thanks for the hard work.

    • Hillel says :

      Stiggler,

      I definitely agree that scrollbars aren’t ideal but I think in most use cases it’s unlikely that a single value will be longer than the width of the entire component. I like your idea of not using the FlowBox for the underline style my only concern is the complexity this will add (and time it will take to implement). The style code is pretty simple right now as all selected items are treated the same (they’re just children of the FlowBox). To make the underlined items wrap they’d need to be text inside a TextArea (which is a whole different can of worms).

      Thanks very much for your input, I think it’s greatly helping in the development of the component.

      Best,
      Hillel

  15. Jerome says :

    Dear Hillel,

    I’ve dream of it, you’ve done it !
    Thanks for listening to our needs and delivering us so rapidly a new version.

  16. Prem says :

    Great work.
    small bug to report. If you use browse to select a value in the sample using Browse, the color doesnt change.

  17. Prem says :

    Anyone got a sample of dynamic data? I added an event listener to “textChange” but it doesnt seem to be working. getRoads is the function that retrieves the data from the server.

    heres my code

    private function onTypeTextChange():void
    {
    if (delayTimer != null && delayTimer.running) delayTimer.stop();
    // only search for inputs of length 3 or more
    if (roadsAC.text.length > 2)
    {
    delayTimer = new Timer(500,1);
    delayTimer.addEventListener(“timer”, getRoads);
    delayTimer.start();
    }
    }

    • Hillel says :

      Prem,

      Thanks for spotting the bug with the demo, I’ll have it fixed in the next release. The issue you’re seeing is caused by another bug. To fix it in AutoComplete.mxml change line 18 from “textChange” to “searchChange” then use the searchChange handler in your application. In the next release I’m going to change this back to textChange.

      Sorry for the trouble this caused you,
      Hillel

  18. Prem says :

    Thank you .
    That did the trick. I changed the event name and recompiled so its working now. I am having another small issue and was wondering if you could help me with that. Now my calls are working and the server side code is executing no problem. But as the searchtext changes and the dataprovider changes the height of the combobox is changing as well and sometimes I get stuck with just one row and no scrollbar even though there are 10s of records if not more than 100.

  19. Prem says :

    Ok let me explain this a little more coz I think I can be a little more specific. If you narrow it down to one item and then “Backspace” (or delete) the last character the server call is made again but the combobox row_count doesnt change. I am looking through the code to see if I can find where I can fix this.

    • Hillel says :

      Prem,

      I’d suggest adding a List component to your app which has it’s dataProvider set to the same dataProvider you’re using for the AutoComplete, this way you can keep an eye on what values are in it. I realize it may be difficult, but if you’re able to post sample code demonstrating the problem I’d be happy to take a look at it.

  20. halflife_baby says :

    Can anyone let me know, what are the ways in which data can be provided to Autocomplete class.

    Also help to do, if country names are provided as dataprovider for Autocomplete class,in output there should be a label called country, which shouldn’t be selectable. under the label country, country names should be displayed which should be selectable.kindly help me.

    • Hillel says :

      Halflife Baby,

      You can pass either an ArrayCollection or an XMLListCollection to the dataProvider property.

      I’m sorry, I’m not sure that I understand your second question.

  21. halflife_baby says :

    Hi Hillel,
    Thank you. My second question is,
    If one Autocomplete class has list of country names to display. If i typed ‘A’ it should display the country names which starts by the letter ‘A’ under the label COUNTRY NAMES..If possible reply me with some examples.
    Kind regards,
    Halflife_baby.

    • Hillel says :

      Halflife Baby,

      If your dataProvider is simply an arrayCollection of strings then it should just work. If however it’s an array of objects then you’ll want to set the labelField to the name of the property for the country name. I’d suggest checking out the examples folder in the zip file.

      • halflife_baby says :

        Hi Hillel,
        Thanks a lot for your reply. Since i am a
        beginner in Flex, i need some sample codings
        for this AutoComplete class. Kindly help me
        with sample codings.Thanks a lot once again.
        Kind Regards,
        Halflife Baby.

  22. halflife_baby says :

    Hi Hillel,
    Again it’s me. I know to connect flex with HSQL DB using java. But while creating ‘Auto Suggest’using Autocomplete component for one Flex application i didn’t get the output.I have used remote object to pass the value to java from flex.Could you kindly help me to solve this?
    Regards,
    Halflife Baby.

    • Hillel says :

      Halflife Baby,

      You haven’t given me too much to go on. Is the remote object correctly returning the data?

      • halflife_baby says :

        Hi Hillel,
        No that’s the problem. while running the application it’s not showing error and at
        the same time it’s not showing the result
        too.
        regards,
        Halflife Baby.

      • Hillel says :

        Halflife Baby,

        I’d suggest using a tool like Charles to monitor the data being sent to your app.

      • halflife_baby says :

        Hi Hillel,
        Thank you for your guidance.Have a nice time.
        regards,
        Halflife Baby.

  23. кpyтoйнoл says :

    Интересная статья, кстати автору хочу предложить установить от яндекс.денег полезную фишку на сайт “Дай рубль”. Я бы дал, так сказать на поддержание. 😉

Trackbacks / Pingbacks

  1. AutoComplete « Mjcprasad’s Blog - July 21, 2009

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: