« Mate Framework - an example | Main | Swiz framework - Custom Metadata Processor »

Using an editable Combobox as itemrenderer

Flex editable combobox can be really useful if you need to let the user select either one of the predefined values or a custom input. The same result can be achieved using a TextInput for custom text and a button that shows a non editable Combobox, but this solution looks less user friendly.
In this post I will show how to use an editable Combobox as itemrenderer in a List. This approach can be not the best (for example you can use an itemEditor) but maybe you will find the same issues using alternative solutions.
Let’s start creating a simple List with an ArrayCollection of CustomObject as dataProvider and using a custom itemRenderer:

Application.mxml


<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;

private var optionsAC:ArrayCollection = new ArrayCollection([
"option1","option2","option3"
]);
[Bindable]
private var myAC:ArrayCollection = new ArrayCollection([
new CustomObject(false,"",optionsAC),
new CustomObject(true,"custom Test",optionsAC),
new CustomObject(false,"",optionsAC,2),
]);
]]>
</mx:Script>
<mx:List dataProvider="{myAC}" width="300"
itemRenderer="customItemRenderer" />

CustomObject.as

package
{
import mx.collections.ArrayCollection;

public class CustomObject
{
public var custom:Boolean;
public var customString:String;
public var options:ArrayCollection;
public var optionIndex:int;

public function CustomObject(c:Boolean = false,s:String = "",o:ArrayCollection = null ,oInd:int = 0)
{
custom = c;
customString = s;
options = o;
optionIndex = oInd;
}
}
}

customItemRenderer.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">

<mx:Script>
<![CDATA[

import mx.events.FlexEvent;

override public function set data(value:Object):void {
super.data = value;
if(!data)
return;
if(data.custom) {
combo.selectedIndex = -1;
combo.text = data.customString;
}
else
combo.selectedIndex = data.optionIndex;
}

private function onComboChange():void {
if(combo.selectedItem) {
data.optionIndex = combo.selectedIndex;
data.custom = false;
} else {
data.customString = combo.text;
data.custom = true;
}
}

]]>
</mx:Script>
<mx:ComboBox width="100%" id="combo" editable="true" dataProvider="{data.options}" change="onComboChange()" />
</mx:HBox>

The customItemRenderer sets the data in the Combobox checking if there is a custom string or a predefined option. onComboChange saves the modified data into the custom objects whenever the user type into the Combobox or select one option from the dropdown list.
This example is straightforward and it could be useful most of the time you need something similar. But what happens if your CustomObject class is bindable?
Let’s modify CustomObject.as adding the Bindable Meta Tag:

[Bindable]
public class CustomObject
{

Now, when onComboChange modify one of the attribute of CustomObject, a change event is dispatched, that brings to an update of the itemRenderer with a call to the set data function. Here the Combobox calls its updateDisplayList that select all the text inside its TextInput. So, if the user is typing, after the first keystroke the text will be selected and a second keystroke will eventually delete the previous inserted text.

Here’s a solution, extend the Combobox component and override its updateDisplayList:


package
{
import mx.controls.ComboBox;

public class CustomCombobox extends ComboBox
{
public function CustomCombobox()
{
super();
}

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
if(editable) {
var begin:int = textInput.selectionBeginIndex;
var end:int = textInput.selectionEndIndex;
}
super.updateDisplayList(unscaledWidth, unscaledHeight);

if (editable)
{
textInput.setSelection(begin, end);
}
}
}
}

The idea is simple, just save the previous selection indexes, than after the Combobox updateDisplayList restore them.
Don’t forget to change the Combobox component used in the itemRenderer with the new custom component.
I think there are many alternative solutions to obtain such interaction but I hope this could be useful to someone to save some time trying to understand why its combobox continue to select its text

This example works in Flex 3.5.

TrackBack

TrackBack URL for this entry:
http://blog.comtaste.com/mt-tb.cgi/117

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

About

This page contains a single entry from the blog posted on May 23, 2010 6:27 PM.

The previous post in this blog was Mate Framework - an example.

The next post in this blog is Swiz framework - Custom Metadata Processor.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33