Making a combo-box in Titanium Appcelerator – code and video

Sometimes we need a true combobox for our projects but iPhone SDK does not have a native one (at least from what I know) and of course neither has Titanium.

So we will build one. A “true” iPhone or Ipad combobox that allows you to use the same textfield to input arbitrary text or select a value from a UIPicker element.

Updated with @CJ_Reed’s screenshot and code at the final of the tutorial.

Let’s see the video first, then we’ll get to work:

Ok, what do we need for this iPhone combobox ?

First of all we need a textField to accept input from the user. Titanium lets you set the leftButton and rightButton for this textField while constructing it. So we will take advantage of this and create a textField as it follows:

var my_combo = Titanium.UI.createTextField({
	hintText:"write your name or select one",
	height:40,
	width:300,
	top:20,
	borderStyle:Titanium.UI.INPUT_BORDERSTYLE_ROUNDED
});

Nothing special, a regular textField with a hint for the user that will disappear when the textField has a value.

Now we need to create the rightButton for it.

We will use a system button provided by Apple (Titanium.UI.iPhone.SystemButton.DISCLOSURE) only that we will rotate it 90 degrees to serve our purpose. This is the code that creates the rightButton and the transformation applied to it.

var tr = Titanium.UI.create2DMatrix();
tr = tr.rotate(90);
 
var drop_button =  Titanium.UI.createButton({
		style:Titanium.UI.iPhone.SystemButton.DISCLOSURE,
		transform:tr
});

Now that we have the rightButton as we need it, the textField constructor becomes:

var my_combo = Titanium.UI.createTextField({
	hintText:"write your name or select one",
	height:40,
	width:300,
	top:20,
	borderStyle:Titanium.UI.INPUT_BORDERSTYLE_ROUNDED,
	rightButton:drop_button,
	rightButtonMode:Titanium.UI.INPUT_BUTTONMODE_ALWAYS
});

Please note the rightButtonMode:Titanium.UI.INPUT_BUTTONMODE_ALWAYS declaration, it makes this button visible all the time.

This is how it looks:

iPhone combobox with Titanium

Pretty sexy, isn’t it? Well we’re not done yet.

Building the modal picker

When the user focuses on the textField, the keyboard appears – so we will have to build our picker to emulate the same behaviour and to maximize the usability of our form. For this we will need a Picker and two buttons: Done and Cancel. These two buttons will be positioned in a Toolbar, again, to emulate as good as possible the keyboard behaviour.

Let’s build everything:

var picker_view = Titanium.UI.createView({
	height:251,
	bottom:0
});
 
var cancel =  Titanium.UI.createButton({
	title:'Cancel',
	style:Titanium.UI.iPhone.SystemButtonStyle.BORDERED
});
 
var done =  Titanium.UI.createButton({
	title:'Done',
	style:Titanium.UI.iPhone.SystemButtonStyle.DONE
});
 
var spacer =  Titanium.UI.createButton({
	systemButton:Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE
});
 
var toolbar =  Titanium.UI.createToolbar({
	top:0,
	items:[cancel,spacer,done]
});
 
var picker = Titanium.UI.createPicker({
		top:43
});
picker.selectionIndicator=true;
 
var picker_data = [
	Titanium.UI.createPickerRow({title:'John'}),
	Titanium.UI.createPickerRow({title:'Alex'}),
	Titanium.UI.createPickerRow({title:'Marie'}),
	Titanium.UI.createPickerRow({title:'Eva'}),
	Titanium.UI.createPickerRow({title:'James'})
];
 
picker.add(picker_data);
 
picker_view.add(toolbar);
picker_view.add(picker);

The code is a little long but is not rocket science. Some stuff to talk about though:

  • Everyting is wrapped inside a view – picker_view – because we will have to animate like the keyboard does, so it’s faster to animate one element only.
  • The height of picker_view is the height of the toolbar (43px) + the height of the picker (208px). How do I know this? I just used a ruler 😀

The combobox interface looks like this:

picker Titanium for combobox

Creating the picker animation

We also need to create 2 animations: slide_in and slide_out. We will animate the bottom property of the picker_view. We will need to start with the picker_view off the screen, so we will build it with:

 bottom:-251

instead of 0 as it was initially.

var slide_in =  Titanium.UI.createAnimation({bottom:0});
var slide_out =  Titanium.UI.createAnimation({bottom:-251});

The logic behind the animations is this:

  • The user focuses the textField – the keyboard appears ( it’s done by the OS , no worries here) and if the picker_view is visible we need to hide it.
  • The user clicks the rightButton – we need to hide the keyboard and show the picker_view.

Here is the code:

my_combo.addEventListener('focus', function() {
	picker_view.animate(slide_out);
});
 
drop_button.addEventListener('click',function() {
	picker_view.animate(slide_in);
	my_combo.blur();
});
 
cancel.addEventListener('click',function() {
	picker_view.animate(slide_out);
});

I also added the click event on the cancel button to hide the picker_view.

Filling the textField with the picker’s value

The only thing we have left is to actually put the value of the picker in the my_combo textField when the user clicks the done button and hide the picker_view.

done.addEventListener('click',function() {
	my_combo.value =  picker.getSelectedRow(0).title;
	picker_view.animate(slide_out);
});

The getSelectedRow method of the picker is returning the selected row, and we use its title. The getSelectedRow argument is the index of the columns in the picker, and since we have only one, this is 0.

Download the project

The Resource folder of the project can be downloaded from here.

Everything is MIT licensed, but as usual, spread the word 🙂

We have an update

@CJ_Reed used this tutorial “to produce multiple selection type data entry in a single window.”
Here is how it looks like:
to produce multiple selection type data entry in a single window.
You can take a look at his code here.
Great work!

Check the Spanish version of this post:
Haciendo una lista de opciones desplegables en Titanium Appcelerator – Código y Vídeo

22 thoughts on “Making a combo-box in Titanium Appcelerator – code and video”

  1. hey,

    thanks for the tutorial, i was looking exactly for this.
    but my problem is that i am trying to display text that i am parsing from a xml file. i’ve used ‘for loop’ to write it as it has some fields to display.

    this is what i have,

    var picker = Ti.UI.createPicker({top:40});
    var data = [];
    var element_category;
    var xhr = Titanium.Network.createHTTPClient();
    xhr.open(‘GET’,’http://joomlaenterprise.cloudmaya.net/plexioffline/index.php?method=getCategories&apikey=plexi&secret=plexicloud.com’);
    xhr.onload = function()
    {
    try
    {
    var doc = this.responseXML.documentElement;
    var category = doc.getElementsByTagName(“category”);
    for (var c=0;c<category.length;c++)
    {
    element_category = category.item(c);
    Ti.API.info("category = " + element_category.text);
    data[c] = Ti.UI.createPickerRow({title: element_category.text });

    }
    }
    catch(E)
    {
    alert(E);
    }
    };
    xhr.send();
    picker.add(data);
    pickerView.add(picker);

    it shows a error at — picker.add(data);
    im not sure of writing the title in that manner. any help on this is appreciated.

    thank u.

  2. Nice tutorial. Do you think to publish others ? I’m developer and I can do some useful tutorials.

    Regards

  3. Sorry for the late reply
    Don’t use

    data[c] = Ti.UI.createPickerRow({title: element_category.text });

    , but

    data.push(Ti.UI.createPickerRow({title: element_category.text }));

    This should fix the problem.
    Let me know.

  4. Its a nice tutorial, but I use TI so that I can deploy to iPHONE and ANDROID. So it would be interesting to see how this output works on android. Otherwise, I would just assume do what you did in a native OC using xCode. But nice tut anyway.

  5. I must admit I only develop for iPhone, so I don’t know how and if it works on Android.
    The objC path is not an easy one( at least for me ), so TI has its place here even you develop for apple devices only.

  6. Very nice tut!
    I have got runtime error TypeError : Cannot set property “selectionIndicator” of null to “true”. In this line :picker.selectionIndicator=true;
    the second error (when I comment the previous line is TypeError : Cannot call method “add” of null. In this line picker.add(picker_data);
    picker_data is not null in the project. Can you help me? thanks. simon (sorry for my english)

  7. It ‘s same as the tutorial :
    var toolbar = Titanium.UI.createToolbar({
    top:0,
    items:[cancel,done]
    });
    var picker = Titanium.UI.createPicker({
    top:43
    });
    picker.selectionIndicator=true;
    var picker_data =[];
    picker_data.push(Titanium.UI.createPickerRow({title:’John’}));
    picker_data.push(Titanium.UI.createPickerRow({title:’John’}));
    picker_data.push(Titanium.UI.createPickerRow({title:’Alex’}));
    picker_data.push(Titanium.UI.createPickerRow({title:’Macih’}));
    picker_data.push(Titanium.UI.createPickerRow({title:’Alsdfdsfex’}));
    picker.add(currentWindow);
    picker_view.add(toolbar);
    picker_view.add(picker);

    I developp for android and I think It does not supported the titanium picker.

  8. I’d like to add something

    http://www.pastie.org/1022745

    that puts the slide up picker code into a reusable object…

    first you would create the “data” for the picker, for example

    var data = Ti.UI.createPickerColumn();
    data.addRow(Titanium.UI.createPickerRow({ title : ‘Today’, value : ‘tdy’, selected : true }));
    data.addRow(Titanium.UI.createPickerRow({ title : ‘Week to Date’, value : ‘wtd’ }));
    data.addRow(Titanium.UI.createPickerRow({ title : ‘Month to Date’, value : ‘mtd’ }));
    data.addRow(Titanium.UI.createPickerRow({ title : ‘Yesterday’, value : ‘yst’ }));
    data.addRow(Titanium.UI.createPickerRow({ title : ‘Last Week’, value : ‘lw’ }));
    data.addRow(Titanium.UI.createPickerRow({ title : ‘Last Month’, value : ‘lm’ }));
    data.addRow(Titanium.UI.createPickerRow({ title : ‘Custom Date Range’, value : ‘cs’ }));

    // Some variables needed:
    var containter = Ti.UI.currentWindow(); // or whatever container we are adding the picker view to

    var triggerControl = Ti.UI.createTextField();

    // Now call the function with
    Pickers.Create(container, triggerControl, data, function(p) {
    // “p” is the picker, use “getSelectedRow” or whatever to get the data chosen ! for example
    triggerControl.value = p.getSelectedRow(0).title;
    });

  9. Hi would like to disable the editing,, I tried to add on the textfield the following attribute
    editable: false,

    but I still see the keyboard and I can edit

    Is there a way to disable the keyboard in order to have a “real” combo box.

    Thank you

  10. Dan, I love your solution, but I’m having a couple of problems. I have the picker within a scrollable view. When slides up, controls on that view show through the picker view. See the results at http://skypanther.com/temp/picker.png

    I have tried setting zIndex:99 and backgroundColor:’#6c8ba9′ on the picker’s view, without improvement. I tried using a ScrollView but then the picker itself, without the wrapper view appears over the top of the entire scrollview blocking any interaction. Any suggestions?

    Thanks,
    Tim

  11. HI Dan,

    I’m a new iPhone developer and need this combo box. Normally, what I know is, we have a .h and .m with .xib file.

    How and where do I put this code to make it run because it’s different on what I know to learn iPhone programming?

    Please help or if possible. please send me a project and let me download and run it. (I”m confuse but interested on this tutorial and I need this)

    Thanks,
    Cris

  12. This is a great implementation of a picker, thanks for posting. I am trying to implement this using the TextField within a Tableview. Unfortunately, I can seem to make the picker visible. The keyboard comes up but when I click on the drop_button the keyboard disappears and no picker. Does anyone have any ideas?

    Thanks,

    James

  13. This is exactly what my project has been needing! Great work, and great article. I stood on your shoulders and packaged this code/component up into an easily plug and play module for ease of reuse.

    http://www.pastie.org/1494046

    Usage is as simple as:

    // Include component in page
    Ti.include(‘../optionPickerDialog.js’);

    // Set data in picker and open as a modal
    optionPickerDialog.setData([
    {title:’Option A’}, {title:’Option B’}, {title:’Option C’}
    ]);
    optionPickerDialog.open();

    // Respond when selection made and dialog closed
    optionPickerDialog.addEventListener(‘close’, function(e){
    if (e.done==true && e.selectedRow){
    alert(‘You selected ‘+e.selectedRow.title);
    }
    });

  14. Update to my component above: http://www.pastie.org/1496406

    The script in the old pastie was crashing the app on the device (worked fine in simulator).

    What I found, after a bit of debugging, is… it seems you MUST add the rows to the picker BEFORE adding the picker to the window. This new code implements this, and seems stable on my device.

  15. Hey Dan, was trialling porting this code to iPad and if you…

    1. Replace “createView” with “createPopover” and
    2. In the rowclick event apply myPopover.show({view:xxx});
    [where xxx is the object to ‘pin’ the popover to]

    It reconfigures to display the picker in a popover. How simple is that!

    cheers,
    Chris.

    P.S. I also added pickerView.hide() to the ‘change’ event for the picker, so it disappears when a value is picked.

Comments are closed.