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

Flex AutoComplete: Almost there… (or so I thought)

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

Latest version

Here’s what’s new:

  • Created new demos: I’ve added two more demos which demonstrate some common ways to use the component. The source for the demos is included in the zip.
  • Added support for a horizontal multiselect: The previous version of the component had a multiSelect mode but it took up a fair amount of screen real estate. I’ve added a multiSelectLayout property which can be set to either “vertical” or “horizontal”. Vertical makes it behave the same as it used to, while horizontal enables you to select multiple items within the TextInput component. I’ve added this option to the demo. I’m still working on this feature, in the next version I’d like to change the style to make it look like the multiselect in Facebook and Mac Mail
  • Improved support for selecting items not in the dataprovider: The best practice to accomplish this is to add a keyDown listener to the component. If the user clicked enter then check if the text property is set and the selectedItem property is null
  • Fixed minor bugs: I’ve gone through all the comments on the blog and tried to address any open issues. I’m sure I’ve missed some things, if you’ve made a suggestion in the past which didn’t make it in to this release please re-suggest it and I’ll try to get it into the next version

One last thing, I’ve added the component to the Adobe Flex Exchange. It’s a relativley new component so it doesn’t have any rating or reviews. If you’re using this component and find it useful it’d be very much appreciated if you could rate it on the site (or even better… write a review).

Thanks very much,
Hillel

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

Flex AutoComplete Component: a new take on an old standard…

While there are a couple of other AutoComplete components out there (most notably the ones from the Flex Team and kuwamoto.org), neither of them had the features we were looking for. I struggled for a while trying to extend them but it just wasn’t working.

One of the main features we needed was for the component to show the part of the string which matches the search term. We also needed it to support selecting multiple items as well as creating an ordered list.

Latest version

As you can see in the demo, there are four main boolean properties which control how the chooser works:

  • isBrowseable: This will display a ‘Browse’ button to the right of the TextInput. If the user clicks it they will be presented with either a searchable DataGrid or a list builder (see below).
  • isMultiSelect: This enables selecting multiple values.
  • isOrderable: This makes the items in the list orderable. It provides buttons to reorder them as well as enabling drag-and-drop.
  • useListBuilder: If this is set to true, when clicking the browse button the user gets a List Builder rather than the DataGrid (note: this requires isBrowseable and isMultiSelect to be true).

Here are the other main properties:

  • labelField: Which property of the data objects to use when displayed in the TextInput and the Lists.
  • labelFunction: In place of the labelField you can specify a function for determining the string to display.
  • dropDownLabelFunction: A reference to the function used to display the matched items in the dropdown. It supports using HTML (which can be used to highlight the part of the string which matches the search pattern).
  • prompt: The message which is initially displayed in the TextInput.
  • filterFunciton: A reference to the function used to search when entering text into the TextInput. The function is passed the object being checked along with the search string
  • isEqualFunction: A reference to a function which can be used to determine if the search string should be considered equal to the object (if it returns true it will automatically select the item).

The bare minimum required to use the component is to set the dataProvider property to an ArrayCollection of objects and specify a value for labelField.

The code for the demo is pretty straight forward.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:hc="com.hillelcoren.components.*"
	width="550" height="400"
	initialize="init()">

	<mx:Script>
		<!&#91;CDATA&#91;
			import mx.collections.ArrayCollection;

			&#91;Bindable&#93;
			public var colors:ArrayCollection;

			private function init():void
			{
				colors = new ArrayCollection(
				&#91;
					{ "name":"Almond", "hex":"#C5E17A" },

					...

					{ "name":"Yellow Orange", "hex":"#FFAE42" }
				&#93; );
			}			

			private function handleChange():void
			{
				var color:Object = chooser.chosenItem;

				if (color != null)
				{
					setStyle( "backgroundColor", color.hex );
				}
			}
		&#93;&#93;>
	</mx:Script>

	<mx:Panel width="100%" height="100%" title="Chooser Demo"
			paddingBottom="20" paddingTop="20" paddingLeft="20" paddingRight="20">
		<mx:HBox>		

			<mx:VBox horizontalAlign="left">
				<mx:CheckBox id="browesable" label="Browesable"/>
				<mx:CheckBox id="multiselect" label="Multiselect"/>
				<mx:CheckBox id="orderable" label="Orderable" enabled="{ multiselect.selected }"/>
				<mx:CheckBox id="listBuilder" label="List Builder" enabled="{ multiselect.selected }"/>
			</mx:VBox>		

			<hc:Chooser id="chooser" dataProvider="{ colors }" labelField="name"
				prompt="Choose your favorite Crayola crayon" width="300" change="handleChange()"
				isBrowseable="{ browesable.selected }" isMultiSelect="{ multiselect.selected }"
				isOrderable="{ orderable.selected }" useListBuilder="{ listBuilder.selected }"/>					

		</mx:HBox>
	</mx:Panel>
</mx:Application>

I consider this to be a version 0.9. It seems to work pretty well but I’m sure there’s a bug or two hiding in there. There are also a couple of more features I’d like to implement.

There’s no copyright… please use the code freely. I just ask that if you come up with any improvements you email them back to me.

Hope you find this component useful,
Hillel

Flex Tip: How to get all items (ignoring the filter) in an ArrayCollection

If you have an ArrayCollection with a filter function set and you loop through the items, you’ll only see the items which match the filter. The catch is sometimes you want to see them all. Initially I was doing the following.

var filterFunction:Function = arrayCollection.filterFunction;
arrayCollection.filterFunction = null;
arrayCollection.refresh();
			
for each (var obj:Object in arrayCollection)
{
	// do stuff
}
			
arrayCollection.filterFunction = filterFunction;
arrayCollection.refresh();

This worked but was pretty ugly. Here’s a nicer approach:

for each (var obj:Object in arrayCollection.source)
{
	// do stuff
}

What I keep finding in Flex is that I’m able to come up with complex code to solve simple problems but when I revisit it months later there’s usually a more straight-forward solution.

Hope this helps,
Hillel

Flex DataGrid: Click once to select, click twice to edit

In the application I’m working on there’s a datagrid which when the user selects a row we update the info on the side page. The catch was we also enabled editing in the datagrid. It was strange to click the row to see the details on the side and then immediately be in edit mode.

Initially we required that the user double-click a field to edit it. The solution was based on the comment provided by Jana in this post.

The concern was that a user may not realize that you needed to double-click to edit the field. In the code provided below the user can select a row by clicking it. If they then click a field in the selected row it will switch in to edit mode.

<?xml version="1.0" encoding="utf-8"?>
<mx:DataGrid xmlns:mx="http://www.adobe.com/2006/mxml">
	
	<mx:Script>
		<!&#91;CDATA&#91;
			import mx.controls.listClasses.IListItemRenderer;
			import mx.events.ListEvent;
			
			private var _selectedRow:int = -1;
			private var _clickCount:uint;
			
			override protected function mouseUpHandler( event:MouseEvent ):void 
			{
				editable = (_clickCount == 2);
				
				super.mouseUpHandler( event );													
			}
			
			override protected function selectItem( item:IListItemRenderer, shiftKey:Boolean, ctrlKey:Boolean, transition:Boolean=true ):Boolean
			{
				var returnValue:Boolean = super.selectItem( item, shiftKey, ctrlKey, transition );
				
				if (selectedIndex == _selectedRow)
				{
					_clickCount = 2;
				}
				else
				{
					_selectedRow = selectedIndex;
					_clickCount = 1;
				}
				
				return returnValue;			
			}
			
		&#93;&#93;>
	</mx:Script>

</mx:DataGrid>

Hope you find this helpful,
Hillel

Problem with data binding in Flex

This issue took me a while to figure out. It looks like errors inside function used for data binding aren’t reported to the Flash debug player. Take this code as an example.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	
	<mx:Script>
		<!&#91;CDATA&#91;
			
			private var _isValid:Boolean
			private var _myString:String;
			
			&#91;Bindable&#93;
			private function get isValid():Boolean
			{
				return _myString.length > 0;
			}
			
			private function set isValid( value:Boolean ):void
			{
				_isValid = value
			}	
		
		&#93;&#93;>
	</mx:Script>
	
	<mx:HBox width="100" height="100" 
		backgroundColor="{ isValid ? 0xFF0000 : 0x00FF00 }"/>
	
</mx:Application>

Based on the code you’d expect the background color to be either red or green. But if you run this the background color doesn’t get set at all. The reason is there’s an error inside ‘get isValid’, since _myString is null checking the value for length fails.

What makes this sort of problem really hard to track down is the compiler doesn’t generate an error when the call to determine the string’s length fails.

Hope this helps,
Hillel

How to get the real location of a point in Flex

When you create a point within a component the Flash player uses the component’s coordinate space. So for example, if your custom component is 200 pixels from the top of the screen and you create a point within it. If you set the point to a Y value of 0 it will be at the top of the component (which means it will be 200 pixels from the top).

Originally I had written a helper class which would recurse its way up the display chain and total up all the values of the X’s and Y’s, but there’s a far simpler way to get the point’s real location.

You can use the localToGlobal function to translate a point’s coordinate space. For more information check out the Adobe docs

Best,
Hillel

Flex Tip: Remove/delete item from an array

Updated March 10th, 2009
It turns out this is probably not the best way to do it. As per the comments below, be careful using the delete command as it will only set the element to undefined (the length of the array won’t be shortened. I considered deleting this post, but I think it may still be useful in that it helps clarify the difference between slice and delete.

Original post starts here…

If you search for this topic you’ll find that this can be accomplished using the splice function.

MyArray.splice(3, 1);

This was how I was doing it for a while, but I just recently discovered a simpler method.

delete MyArray[3]

Hope this helps,
Hillel

Flex Tip: Error accessing the stage when the app first loads

Long story short use the applicationComplete event.

This is something I struggled with for a while. I don’t use a mouse much and like to code keyboard shortcuts into the applications I build. My code initially looked like this: