Give us a call 203-379-0773
Check out our Angular Book Series.

A Flex AutoCompleteMultiSelect Component

I am surprised to announce a brand new Flextras component. A consulting client wanted an AutoComplete component which would allow multiple items to be selected in the drop down. So, I built them one. This component is an extension to the Flextras Spark AutoComplete component that allows for multiple items to be selected in the drop down. The new component has a few variations, so let's talk about them.

Getting the Code

Ever since we shut down the Flextras store, we are no longer updating binary builds on the Flextras web site. You can get the updated code from our GitHub repository. I recommend building it into a SWC with a Flex Library project. Here are instructions to do that from Flash Builder:

  1. Create a Flash Builder Library Project
  2. Put the Spark directory into the Flash Builder Library Project's source directory.
  3. Include design.xml and manifest.xml in project [Optional]
    1. Bring up project properties on your Library Project
    2. Select Flex Library Build Path
    3. Select Assets
    4. Select design.xml and manifest.xml
  4. Set up namespace URL [Optional]:
    1. Bring up project properties on your Library Project
    2. Select Flex Library Compiler
    3. Click Browse next to manifest file; and select the manifest file on your disc
    4. Enter "http://www.flextras.com/mxml" in the namespace URL box
  5. From the Project menu select Clean; and your Library Project's bin directory should have built a SWC.

Now you can add the library project, or generated SWC, to the library path of a main Flex project to create the application.

Generic AutoCompleteMultiSelect

Once you have the library SWC compiled, you create a simple application to demonstrate the AutoCompleteMultiSelect like this:

<?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"
             xmlns:flextras="http://www.flextras.com/mxml">

    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            [Bindable]
            public var dataProvider : ArrayCollection = new ArrayCollection([
                {label:'Alabama',data:1},
                {label:'Alaska',data:2},
                {label:'Arizona',data:3},
                {label:'Connecticut',data:7},
                {label:'Delaware',data:8},
                {label:'Florida',data:9},
                {label:'Oklahoma',data:36},
                {label:'Oregon',data:37},
                {label:'Pennsylvania',data:38},
                {label:'Wyoming',data:50},
                
            ]);
        ]]>

    </fx:Script>
<flextras:AutoCompleteMultiSelect dataProvider="{this.dataProvider}"/>
</s:Application>

This demo application starts with the Application tag, as Flex applications often do. There is a script block which creates an ArrayCollection as a dataProvider. Then there is the AutoCompleteMultiSelect component. The AutoCompleteMultiSelect will be in the flextras namespace if you compiled it as per previous instructions. Specify the dataProvider on the AutoCompleteMultiSelect instance and run the application:

The AutoComplete input is put inside the drop down with the default skin. You can type inside it to see the list get filtered:

You can select an item by clicking on it. You can use the control key when clicking to add items to a selection. When you want to select a range, then select the first item and hold down the shift key when clicking the second item. All items between the first and second item will be selected. This is probably what you are used to from the Flex list. The selected items will show up visually in the drop down, and also show up in the prompt area:

The items are separated by a comma; however you can change it using the delimiter property on the component. Go play with this sample or get the source.

It is worth nothing that the component also exposes all the selected items using a savedSelectedItems property. If you need to access all the selected items, this is the best way to do so. The selectedItems or selectedIndices properties relate back to the dataProvider, which may have filtered out selected items if you have typed something in the AutoComplete input.

Use the component as an MultiSelectDropDownList

In the process of developing this component, I also created a skin without the AutoComplete functionality, essentially creating a MultiSelectDropDownList. The skin is named DropDownListMultiSelectSkin.mxml and is located in the spark.flextras.autoCompleteMultiSelect directory.

You can create a new application, similar to the previous one and just set the skinClass property on the AutoCompleteMultiSelect component

<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"
             xmlns:flextras="http://www.flextras.com/mxml">

    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            [Bindable]
            public var dataProvider : ArrayCollection = new ArrayCollection([
                {label:'Alabama',data:1},
                {label:'Alaska',data:2},
                {label:'Arizona',data:3},
                {label:'Connecticut',data:7},
                {label:'Delaware',data:8},
                {label:'Florida',data:9},
                {label:'Oklahoma',data:36},
                {label:'Oregon',data:37},
                {label:'Pennsylvania',data:38},
                {label:'Wyoming',data:50},
                
            ]);
        ]]>

    </fx:Script>
<flextras:AutoCompleteMultiSelect dataProvider="{this.dataProvider}"
skinClass="spark.flextras.autoCompleteMultiSelect.DropDownListMultiSelectSkin"/>

</s:Application>

Run this application to see the working app:

Open the drop down by clicking the button, and select a few items. You should see something like this:

You can play around with the live application. or get the source.

Adding a Checkbox Renderer

I created one other component in this new round of Flextras development. My client wanted a renderer with a checkbox that would represent the state of an item. I created a CheckboxAutoCompleteRenderer.as in the spark.flextras.autoCompleteMultiSelect.renderers directory. You can use it in an application like this:

<?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"
             xmlns:flextras="http://www.flextras.com/mxml">

    
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            [Bindable]
            public var dataProvider : ArrayCollection = new ArrayCollection([
                {label:'Alabama',data:1},
                {label:'Alaska',data:2},
                {label:'Arizona',data:3},
                {label:'Connecticut',data:7},
                {label:'Delaware',data:8},
                {label:'Florida',data:9},
                {label:'Oklahoma',data:36},
                {label:'Oregon',data:37},
                {label:'Pennsylvania',data:38},
                {label:'Wyoming',data:50},
                
            ]);
        ]]>

    </fx:Script>
<flextras:AutoCompleteMultiSelect dataProvider="{this.dataProvider}"
                                     itemRenderer="spark.flextras.autoCompleteMultiSelect.renderers.CheckboxAutoCompleteRenderer"/>


</s:Application>

The only change in this from the original sample is that it includes an itemRenderer on the AutoCompleteMultiSelect.

Select a few items to see the checkbox work. The interesting thing about this renderer is that if you click the checkbox, you do not have to use the control key to select multiple items in the drop down:

The CheckBox Renderer also has AutoComplete functionality, and will highlight the typed text inside the renderer's label display:

You can check out a running sample or get the source.

Final Thoughts

Since we shut down the Flextras store, I didn't think I'd be spending much more time on it, but a client came along with some specific extensions to our component set and I was happy to work with them to make these changes, and I'm equally happy to share them with the Flex community. I hope you find them useful.

We are willing to entertain similar requests from other clients if you have a need be sure to email us to discuss.

Kickstarter Plans for Flextras AutoComplete - 12/7/2012 - Episode 150 - Flextras Friday Lunch

I took last week's Flextras Friday Lunch session, to talk about the changes I Want to make to our AutoComplete as part of our Kickstarter, if the Kickstarter project gets funded. There are only a few more days left and a long way to go, so if you're interested in this project, we're running out of time to fund.

Flextras Friday Lunch is a short demo followed by open Q&A that occur the first and third Friday of every month at 1pm EST. The presentations take place over Connect. You can find out what time this occurs in your own time zone at TimeAndDate.com.

I hope I can help answer some of your questions at the next one.

Notes

A look at our AutoComplete Code - 11/21/2012 - Episode 150 - Flextras Friday Lunch

This wasn't quite a Flextras Friday Lunch, since I held it on Wednesday. But, I used the same infrastructure. This time I demonstrated our AutoComplete component, and took a look at the code that lies behind the component. Since I did have the recording, I thought I'd post it here.

Flextras Friday Lunch is a short demo followed by open Q&A that occur the first and third Friday of every month at 1pm EST. The presentations take place over Connect. You can find out what time this occurs in your own time zone at TimeAndDate.com.

I hope I can help answer some of your questions at the next one.

Notes

Check out the Flextras AutoComplete KickStarter

Did you ever wish that the Flex Framework had a native Autocomplete Component? Do you wish you had easier access to the source of the Flextras AutoComplete? Do you want to help make those things happen?

Now you have a chance to answer all three questions as a yes.

We have launched a KickStarter campaign to do just that. If funded, we are going to expand the API of our Spark AutoComplete and donate all the code to Apache Flex.

This is an experimental approach to funding our love for creating Flex components. If you like the idea, then go check out the Kickstarter and let's make this happen.

Flextras Flex AutoComplete Component Update

We pushed up new release builds of our Flex AutoComplete component last night. This includes a bunch of bug fixes throughout the product line:

In our MX AutoComplete:

  • Added version compiled against Flex 4.5
  • Fixed bug where cursor location was not being set properly if a mouse was used to select items.
  • Fixed 4.5 issue where border around TextInput would vanish.

In our free Spark AutoComplete:

  • Fixed Bug where selectedIndex and selectedItem would change during a copy operation.
  • When setting the dataProvider to null; we fixed bug where selectedIndex / selectedItem did not reset themselves automatically.
  • Stopped weird scrolling issue unique to Flex 4.5

We also refreshed the Mobile AutoComplete version to the latest from our Mobile Component set.

Check out the full release notes for the details; and as always you can download the developer edition to test them out for yourself in your own application.

HTML in Mobile Apps - 7/29/2011 - Episode 108 - Flextras Friday Lunch

In this episode I took at the Flextras AutoCompleteComboBox component and how the different versions, including our mobile version, use HTML to highlight the typed text in the drop down list.

The attendees ask about AIR Badge Installers and we discuss the differences of Mac vs PC. Flextras Friday Lunch is a short demo followed by open Q&A that occur the first and third Friday of every month at 1pm EST. The presentations take place over Connect. You can find out what time this occurs in your own time zone at TimeAndDate.com.

I hope I can help answer some of your questions at the next one.

Notes

Contact

Our Flex AutoComplete Component supports Mobile Devices

The release builds for our Flex AutoComplete Component have been updated, and they now include mobile support devices.

You can view the full release notes.

At this time, the mobile support is only included for customers who have purchased the full Unlimited Domain Edition of our AutoCompleteComboBox.

Customers who have purchased our AutoComplete component can sign into their account and download the latest version from their purchase history section.

I you want to purchase, you can get it here.

Developer editions of our Flex AutoComplete component are available for free download.

Free Developer editions of our mobile components will be coming soon as part of the Flextras Mobile Component Set.

Why doesn't my Mobile Skin show focus properly?

I'm working hard on a mobile version of the Flextras AutoCompleteComboBox. I spent some time building out an ActionScript only skin that extended the MobileSkin class.

Unfortunately, I was having a weird issue. The focus ring was not showing up properly. I was seeing this:

You'll notice that the blue focus ring shows up on top of the component, but does not show up below it.

I wanted to see this:

Which shows the focus ring correctly highlighting the whole component. The above screenshot was taken with an 'early' MXML version of the mobile skin.

Why would this work for an MXML skin, but not for an ActionScript skin that was almost identical?

It turns out, the issue was I did not implement a measure method; so no measuredHeight or measuredWidth were being set. Once I implemented that method; my focus issues went away.

Flextras AutoCompleteComboBox on Flex 4.5; Use it For Free

I just updated the release builds Flextras AutoComplete Flex Component. This is a minor update, and includes a fix for a bug that only showed up in Flex 4.5.

The Free Edition Download now includes both the Flex 4.5 and Flex 4 version. You can read the release notes for full details.

For those who want the source, we added a more cost effective way to get the source for our Spark AutoCompleteComboBoxLite. You can pick it up for just $49.

The pricing on our full AutoCompleteComboBox package remains unchanged. In addition to including the full source code for the Spark component, it also has:

  • The Full Source for our MX AutoCompeteComboBox
  • MX versions compiled against Flex 3, 3.5, and 4 SDKs.

You can pick up the full package here. Those that purchase the Full package will get a free upgrade to our Mobile AutoCompleteComboBox coming later this month. Remember, you can always try before you buy by downloading our developer editions; which are fully functional.

Building Mobile Skins in Flex 4.5

Flex 4.5 was recently released, and one of the big pushes for that is mobile support. When building mobile components, we want to build ActionScript Skins for them instead of MXML skins, as we did with Flex 4 and Flex 4.1. This is a bit of a change for us, as Adobe always pushed us to use MXML when creating skin classes.

I believe that the push to use ActionScript over MXML is due to performance. MXML is really just an ActionSript code generation language; and sometimes it does some unexpected things under the hood. Writing skins in ActionScript is one way to avoid the potential wonkyness that may occurs when MXML is turned into ActionScript.

MobileSkin Class

To help build skins, there is a new MobileSkin class as part of the SDK. This is a class that extends UIComponent and provides a bunch of methods to help us build mobile skins. As best I can tell, there is no penalty for not extending the Mobile Skin class. You could extend UIComponent or some other Flex component to create your skin. But, unless you have a compelling reason to break convention, I'd stick with what adobe recommends.

Extra MobileSkin Methods

MobileSkin provides some special methods that you can override or extend. The extra methods are not much different, conceptually, than the Spark methods such as partAdded() and partRemoved(). These are some of the extra methods:

  • layoutContents(): The layoutContents() method is used to size and position the children of your component. It is called from the updateDisplayList() method.
  • drawBackground(): The drawBackground() method is used to create your background graphics. It is called from updateDisplayList(). In the mobile skin for our upcoming mobile AutoCompleteComboBox we use graphics.drawRect() to create a background on the popup. This is a replacement for the MXML Graphics used in the default ComboBox skin.
  • commitCurrentSkinState(): The commitCurrentSkinState() method is used to help implement states. Whenever the state changes, the commitCurrentSkinState() method is called. States in a Mobile Skin should not be implemented as real states that extend the state class, with multiple overrides to change things. Instead they should be implemented procedurally within the skinClass. You should tie into the component lifecycle methods to make the relevant changes to properties, styles, positioning, and layout. This method is called from the currentState set method.
  • hasState(): The hasState() method is a helper method that you should implement. It can tell people using your skin class whether this skin class implements a certain state, or not. As best I can tell this is primarily used for people extending your mobile class. I envision it being important to the extensibility of the class; but you may let it slide by the wayside if you're building a single use component.

There are also a few methods which I consider helper methods. They aren't implemented for you to extend, but are rather implemented to help you solve a specific task quickly:

  • setElementSize(): The setElementSize() method is a helper for setting the size of a child. This handles the differences between child types, such as ILayoutElement or IFlexDisplayObject. The documentation recommends you always set an elements size before setting its' position.
  • setElementPosition():The setElementPosition() is a helper method for setting the x and y values of a child. This handles the differences between child types, such as ILayoutElement or IFlexDisplayObject.. Documentation states you should always set the elements size before setting its' position.
  • getElementPreferredHeight(): This method is used to get the preferred height of the child. If the child is an ILayoutElement, then the getPreferredBoundsWidth() value will be returned. If it is an IFlexDisplayObject, then the measuredWidth will be returned. If the object is neither of those, then the height of the object is returned.
  • getElementPreferredWidth(): This method is used to get the preferred height of the child. If the child is an ILayoutElement, then the getPreferredBoundsHeight() value will be returned. If it is an IFlexDisplayObject, then the measuredHeight will be returned. If the object is neither of those, then the width of the object is returned.

These methods help encapsulate setting the size and position of your child, no matter what the type of the child is.

MobileSkin extends UIComponent

I mentioned earlier that the MobileSkin class extends the UIComponent class. This is important because it means that to implement our layouts; we can tie into the same component lifecycle methods that we're used to using from learning the Halo Architecture:

  • createChildren(): The createChildren() method is the method you use to create your component's children. It is called automatically during the lifecycle creation.
  • commitProperties(): commitProperties() is used to coordinate property changes in a component. It is a bit of a wild card method, and what you do with this will relate specifically to what properties are changing, and how they change.
  • measure(): The measure() method is used to determine the ideal height and width of a component. It sets the measuredWidth and measuredHeight properties. OF course, a component is always sized by its' parent, and it is up to the parent to use these values or not. I believe al Flex Framework containers will honor these values if possible.
  • updateDisplayList(): The updateDisplayList() method is used to position and size the children of a component. When extending a MobileSkin you'll probably use layoutContents() and drawBackground() instead of updateDisplayList() directly.

The HostComponent Property

In Flex 4 when we created a skin, we would specify the component class that this skin accessed using the hostComponent metadata. It looked something like this:

<fx:Metadata>
[HostComponent("mobile.flextras.autoCompleteComboBox.AutoCompleteComboBox")]
</fx:Metadata>

We do not use metadata to define the host component in an ActionScript skin. Instead we create a property named hostComponent. The properties type should be of the component class that the skin was designed for. I would use something like this:

public var hostComponent: AutoCompleteComboBox;

The hostComponent property is set automatically during lifecycle creation. It gives the skin class a hook into the component class. As one example of a use case, our AutoCompleteComboBox mobile skin uses the hostComponent property to reference the number of items in the dataProvider, and uses that to determine the size of the drop down.

Final Thoughts

Building Mobile Components feels like a nice intersection where the Spark and Halo component architectures meet. You'll need to know both lifecycles in order to be successful at creating components for use in Mobile development.

More Entries