views:

3184

answers:

5

How can you make a ComboBox where the user can select null?

If you simply create a combobox with null in the dataprovider, the value appears but the user cannot select it:

<mx:ComboBox id="cb" dataProvider="{[null, 'foo', 'bar']}" />

Is there a way to make that null selectable?

A workaround is to add an item into the dataProvider that is not null but 'represents' null; and then map between null and that object every time you access the combobox. But that's not really an elegant solution; you would always have to keep this mapping in mind in all code that accesses a 'nullable' combobox...

Edit: expanding on why I don't like the workaround: It could be done in a subclass of course, but either I introduce new attributes (like nullableSelectedItem); but then you have to be careful to always use these attributes. Or I override ComboBoxes selectedItem; but I'm affraid that is going to break the base class: it might not like something changing its idea of what the current selected item is from within. And even this fragile hack works, on top of selectedItem and dataProvider this nullItem then also needs to be handled special in data and listData for renderers, in labelFunction, and then it's probably still being exposed in events the ComboBox sends... It might work, but it's quite a hack just to fix the problem that if the user clicks on the item it isn't activated (for the rest the ComboBox handles null fine). (Another alternative is to have a ui component delegate to a ComboBox, but that's even much more code just to avoid this small problem)

+1  A: 

Hi,

Unfortunately, this is impossible. How ever, a good solution that will not make you "have to keep this mapping in mind" is to create a class inherits from ComboBox with its own DataProvider property.

this property setter will handle the null values and have a representation for it on the super ComboBox class.

yn2
I don't really like it. But as long as nobody comes up with something that makes a "real" null selectable, I guess you're right: it is impossible, and the best we can do is encapsulate the workaround as much as possible in a subclass.
Wouter Coekaerts
+2  A: 

The following solution is likely the simpliest one:

<mx:ComboBox id="cb" dataProvider="{[{label:"", data:null}, {label:'foo', data:'foo'}, {label:'bar', data:'bar'}]}" />

and access the data using cb.selectedItem.data

However, this simple solution is not binding-friendly, as Wouter mentioned.

So here is a more tricky solution that will allow selecting null objects:

<mx:ComboBox id="cb" dataProvider="{[null, 'foo', 'bar']}" dropdownFactory="{new ClassFactory(NullList)}" />

Where NullList is the following class:

package test
{
import mx.controls.List;

public class NullList extends List
{
    public function NullList()
    {
     super();
    }

    override public function isItemSelectable(data:Object):Boolean
    {
     if (!selectable)
            return false;
        return true;
    }

}
}
Hrundik
That is a simplified version of the workaround. But this doesn't event allow you to bind the selectedItem to a model. In other words, you can't do something like <mx:Combobox ... selectedItem="{model.currentProduct}" /> with this.
Wouter Coekaerts
Yes, you're right, binding will be harder for that solution. (but it's still possible - you can bind to selectedIndex and use a simple function to get item index).I've come up with the solution which solves your exact problem. Hope that helps
Hrundik
Nice! Exactly what I was looking for.It does have one cosmetic issue: the null item does not light up when hovering the mouse over it.
Wouter Coekaerts
Yep, I'll try to find some time to fix it in a couple of days. It's even more complicated, cause it happens somewhere deep inside List (or even ListBase) component.Feel free to post your own answer if you figure how to fix it yourself.
Hrundik
A: 

A really simple, but also very limited solution is to add a prompt="" attribute..

This will prevent the ComboBox from selecting the first item in the dataProvider automatically, but as soon as the user select an item, the empty row will not be displayed anymore.

Cosma Colanicchia
Being able to still select the empty row is quite essential, it what the whole question is about.
Wouter Coekaerts
Supporting this scenario requires some complex coding.. Please take a look at my other answer.
Cosma Colanicchia
+1  A: 
Cosma Colanicchia
Your code for automatically adding it, and watching the original collection for changes looks good.But as I explained in the question, I really don't like having an emptyItem 'representing' null; and with the NullList proposed by Hrundik that is not needed anymore.
Wouter Coekaerts
If you control the creation of your dataprovider collections (and thus you have the chance to add the null one), the solution suggested by Hrundik is the way to go (big fan of the KISS principle here :)My subclass is not about having a real object instance vs a null reference (it could be rewritten use the null item / dropDownFactory method).It is more focused of managing this things when your collection could be refreshed at any time and you're not in control of this, which is a pretty common scenario. I Hope it could be useful if someone is dealing with the same issue.
Cosma Colanicchia
A: 

@Cosma: Genius. Thank you very much.

David Cox
Tip: Please add comments on answers by adding a comment on the answer ("add comment" link) and not by answering the original question. Thanks.
Wouter Coekaerts
Anyway, thanks :P
Cosma Colanicchia
@Wouter: He cannnot comment answers yet due to reputation (probably just signed up)..
Cosma Colanicchia