If you have a list of items for users to choose from, why not just use a ComboBox? That is a perfect solution if your list of items is relatively small, but what if you have 50 items? AutoComplete can speed up the time it takes to get to what you want and that always makes users friendly.

The Demo


This demo uses a hard coded array of objects through which the user will search for their favorite fruits. To see how it works, type in the letter P. It is not case sensitive as you will see when we dissect the code. You get a list with four fruits that start with the letter P. Now, type in an E, so that you have PE. The list of four reduces itself to a list of two. At anytime you can select one of the choices from the list and the information for that fruit will be displayed below. So, what is the Search button for you might be thinking? Well, try this. Suppose you want to search for melons. Type in the the letter M. None of the results displayed in the List is Melon. Type in the next letter E, and the List disappears. You might be thinking that there are no melons available, but continue typing until you have the entire word melon in the search field. Now click the Search button. You will see two results in the list that were not available before. We'll be getting into all the gory details shortly.



The Demo Files

Download the autoComplete.zip. Included in this file is the autoCompleteDemo.fla, the AutoDemo.as, and the AutoComplete.as. The AutoComplete.as class is found in the folder system ca.xty.myUtils. If you have your own class library, you can move this class into the appropriate folder - just remember to change the package details in the class to match your folder system.

The files are made in Flash CS5, but if you are using CS4 do not run off! The AS class files do not care what version of Flash you have. In order to use these files all you will need to do is make yourself a new fla. The fla you create can be called anything you want. Set it's width to 500 and it's height to 300. Put a copy of the List and Button components in the library and set the Document Class to AutoDemo. Make sure all the files are in the same folder and you are good to go.

In the autoCompleteDemo.fla you will see that there is nothing on stage. Looking in the library, you will see that we have included a Button component and a List component. Also notice that the Document Class is set to AutoDemo - no .as extension. And that is it for the fla. Next, let's take a look at the Document Class, AutoDemo.as.

Document Class

The Document Class is what runs the show. It gathers all of the necessary classes in it's import statements and sets up the display area. Let's start right at the top.

package  {


The package statement is very simple because this class is in the same folder as the fla.

import flash.events.*;
import flash.text.*;
import flash.display.*;
import flash.geom.*;
import ca.xty.myUtils.AutoComplete;


Below that we import the goodies we need. The asterisk is a wild card, which indicates that we are importing all the classes from a certain package. This is fine since the compiler only includes the actual classes it needs when you publish the fla. Just to show you how you can target one particular class, the last import statement only gets the AutoComplete class from the package system ca.xty.myUtils.

public class AutoDemo extends Sprite{
        private var ac:AutoComplete;
        private var fruitArray:Array = [{label:"Apple", Type:"Pome", Description:"The fruit is developed from a compound inferior ovary. The ripened tissue around the ovary forms the fleshy edible part."}...];

        private var bg:Sprite;

        private var t1:TextField;
        private var t2:TextField;
        private var it1:TextField;

        private var titleFormat:TextFormat;
        private var titleFormatW:TextFormat;

        private var xPos:int;
        private var yPos:int;


Now we declare our class AutoDemo and set it to extend the Sprite class. Next we create our variables.

The first variable is an instance of our AutoComplete class called ac.

Next we have our array, which as I said earlier is hard coded here for convenience. Here I am only showing enough for you to note the structure of it. It is an array of Objects, with each object containing the following properties: {label:"Apple", Type:"Pome", Description:"The fruit..."} The curly braces declare that this is an Object. The name/value pairs are familiar if you have created such objects for the ComboBox or List components.

Then we have a variable which is a Sprite and will serve as our header background.

After that, we have 3 TextFields, and two TextFormats.

Lastly we have two variables which we will use to hold our x and y positions. Using these it is easy to move things around in a block. Suppose that for some reason you decide you want the whole works to be set at 10 pixels lower. With the xPos, yPos system in place all you have to do is change the first yPos from 0 to 10 and everything shifts downward. In a set up with dozens of display objects on the stage this can be a great time saver.

public function AutoDemo() {


This sets up our constructor function for the AutoDemo class.

addEventListener(AutoComplete.MADE_CHOICE, setDisplay);

titleFormat = new TextFormat();
titleFormat.color = 0x000000;
titleFormat.size = 12;
titleFormat.font = "verdana";
titleFormat.align = "left";

titleFormatW = new TextFormat();
titleFormatW.color = 0xffffff;
titleFormatW.size = 12;
titleFormatW.font = "verdana";
titleFormatW.align = "left";

xPos = 0;
yPos = 0;

bg = createSprite(0x004083, 500, 60, xPos, yPos);
addChild(bg);

xPos += 20;
yPos += 5;

t1 = new TextField();
t1.x = xPos;
t1.y = yPos;
t1.width = 200;
t1.height = 20;
t1.text = "Look up your favorite Fruit";
t1.setTextFormat(titleFormatW);
addChild(t1);

yPos += 25;

t2 = new TextField();
t2.x = xPos;
t2.y = yPos;
t2.width = 50;
t2.height = 20;
t2.text = "Search:";
t2.setTextFormat(titleFormatW);
addChild(t2);

xPos += 55;

ac = new AutoComplete(fruitArray, "label", 150, 20, 0xffffff);
ac.x = xPos;
ac.y = yPos;
ac.addEventListener(AutoComplete.SHOW_LIST, listDepth);
addChild(ac);

xPos += 25;
yPos += 35;

it1 = new TextField();
it1.x = xPos;
it1.y = yPos;
it1.width = 300;
it1.height = 80;
it1.type = "input";
it1.multiline = true;
it1.wordWrap = true;
it1.autoSize = TextFieldAutoSize.LEFT;
addChild(it1);
}


The first thing we do inside the constructor is set up an event listener. This will listen for an event which is dispatched from the AutoComplete class once a user has made a choice. We'll look a little closer at this when we get to the setDisplay function.

Next we give our TextFormats a few properties.

Now we set our initial xPos and yPos vars to 0.

Then we draw our header background using the createSprite function, which is described further down.

With our header in place, we adjust the xPos by 20 and the yPos by 5. This sets up the placement of our first TextField, t1, which is just a title field. Since the header background is a dark blue we use the TextFormat titleFormatW, which uses white as the text color.

We want the next TextField, t2, right underneath t1, so we simply adjust the yPos by 25 and leave the xPos alone. Now we add in t2 and adjust our xPos by the t2 width plus 5 for a little gap, because we want our instance of AutoComplete to line up right beside the t2 field.

Our variable ac gives birth to a new instance of AutoComplete, and passes in some property values via the constructor. The first parameter passed is the array we are using. The next parameter is the name of the property within the object whose value we want to search for. Sending this as a parameter gives you additional flexibility. Depending upon the nature of your information, you may have properties within your array objects such Name or Description. If you want to use these values to search in, just pass them as a string, "Name". The "label" is probably the most common property you will use, but not necessarily the only one. The next two properties are the width and height of the search TextField you want to create. The last property is defined as optional because in the AutoComplete class this property is set with a default value. This number represents the search button text color. The default is black, so, because our header is dark blue, we will set this properties' value to white.

Then we position our instance on stage using the xPos and yPos values.

The event listener waits to hear from the AutoComplete class that it needs to adjust the depth of the instance in order to show the List above everything else on stage. The way the display list works, each object is added one after another starting at the bottom. In our case the it1 TextField is at a higher depth than our ac instance. So, when the ac instance makes the List component visible it would be underneath the it1 TextField. The listDepth function takes care of this problem each time this event is fired. You could simply add the it1 TextField before adding the ac instance, but suppose you have display objects that are set up dynamically once the user makes a choice? For instance, in the project I made the AutoComplete for, a series of buttons are added to the stage once the user picks something from the search field. These buttons will always be put on stage at a higher depth than the instance of the AutoComplete.

I wanted to center the it1 TextField so I added 25 to the xPos and 35 to the yPos to bring it below the header background.

The it1 TextField has the multiline and wordWrap properties set to true, so that by using an autosize value of LEFT we can force the TextField to expand down if we encounter more text than we have room for.

private function listDepth(e:Event):void{
            setChildIndex(ac, numChildren - 1);
}


Here is our listDepth function which is called when an event is dispatched from the AutoComplete class telling us basically that the List component is now going to be visible so you had better make sure it is on top. We do this using the setChildIndex, which takes two parameters: the child to be re-indexed, and the depth at which we want it to be placed. In our case we want this depth to be the highest we can get. We take the total number of children on the stage and subtract one from that integer. We subtract the 1 because the display list, like an array, is zero based. So, if numChildren equals 3, then the occupied depths are 0, 1, 2. The numChildren - 1 gives us the top position. Everything else on the stage is simply pushed down.

private function setDisplay(e:Event):void{
            var fIndex:int = ac.aIndex;
            if(fIndex == -1){
                it1.text = ac.noResult;
                it1.setTextFormat(titleFormat);
            }else{
                it1.htmlText = "<b>Fruit Type:</b> " + fruitArray[fIndex].Type + "<br/><br/><b>Description:</b> " + fruitArray[fIndex].Description;
                it1.setTextFormat(titleFormat);
            }
    }


The setDisplay function is also fired through an event dispatched in the AutoComplete class. This time the event is telling us that a choice has been made by the user, please display it now.

In the AutoComplete class we have a public variable called aIndex. Because it is public we are able to pull it into our Document class by setting the fIndex variable to the value of the ac.aIndex variable. If fIndex is equal to -1, then we have no result to display, and so we set our it1 Textfield to read the noResult message from the instance ac by using the same dot syntax which gave us access to the aIndex variable. However, if fIndex does not equal -1, then we have something to display. The fIndex variable represents the index number of the chosen item from our fruitArray. All we need to do to get the right information is pull it out of the fruitArray using this index. So, we are going to set it1's text field to accept html text and then put together the string. From our fruitArray we pick the object in the fIndex position within the array and grab the property Type, and then the property Description.

private function createSprite(color:int, w:int, h:int, x:int, y:int):Sprite{
  var s:Sprite = new Sprite();
  s.graphics.beginFill(color);
  s.graphics.drawRect(0, 0, w, h);
  s.graphics.endFill();
  s.x = x;
  s.y = y;
  return s;
}


The createSprite function draws a simple rectangle for us. The parameters are, color, width, height, x position and y position. The graphics class uses this information to draw a rectangle and returns us a nice shiny Sprite.

And that is it for our Document Class. Now let's jump into the AutoComplete class itself.