PDA

View Full Version : Combo with first entry "null"



jsakalos
8 May 2007, 2:06 PM
Sometimes I want to use combo for displaying options taken from one database table to be entered as values to another database table.

It is often necessary to have entries from options table plus a null value (displaying e.g. "---") standing for "unspecified", "unknown".

In my PHP programming era I have created the combo class with the option firstNull that automatically prepended the list with this null/--- entry.

Do you have any ideas how to solve it in Ext?

jsakalos
8 May 2007, 4:46 PM
I have found solution myself and it's not Ext but SQL solution:



select null as fieldID, '---' as fieldName
union
select fieldID, fieldName from fields



Hope it helps someone.

waterlowa
15 May 2007, 5:04 PM
Wish I saw this post yesterday!!! Took me 2 hours last night fiddling with combo.store.add() and insert() methods without any luck. And finally I had to come to the same server approach (:|

I also found that the combo doesn't like selecting null values. I have a null value and 'All' text from the server. I want the option 'All' to be pre-selected. I tried



combo = new Ext.form.ComboBox({
fieldLabel: 'State',
hiddenName: 'stateid',
store: ds,
valueField: 'value',
displayField: 'text',
typeAhead: true,
triggerAction: 'all',
value: ''
});

and



combo.setValue('');

(Also tried using null instead of '') But both didn't work. Then I went out one step and changed the null value to 0 from the server and it still would not pre-select 'All'.

At the end I changed the config in the combo.



value:'All'


and it worked.

gnapse
19 Jun 2007, 4:28 AM
This is something I need sooooo much. I hate the server-side solution because is conceptually wrong. I have a set of data and I need a combo box to select one item from it, or to select none. I need just that, a sort of option for the combo to automatically include a 'none' option above. Including that option in the data just doesn't seem right.

Please, don't take me wrong. The server side solution might work for some cases. But I desperately need the client-side solution built-in to the combo. My ajax backend is used by several other frontends and I don't think I should change its interfaces.

The Ext combo is great, but it does not serve as a replacement for the HTML select. It should be an extension for the classic select element, but it isn't. With the select this was straightforward.

I've tried to subclass the combo to achieve this, but it is like hell. It seems that the combo delegates the handling of items to an instance of Ext.View, which is the one that actually retrieves data from the data source and shows items.

Jack, can you please, help me on this? I am not asking you to do it, but just to point me in the right direction.

tryanDLS
19 Jun 2007, 8:14 AM
Why is this a difficult problem? Load your data from the server. In the load handler, insert an additional row in the store with a key value lower than your lowest value (e.g. 0) and display value of 'None' or whatever you want. If you were building an HTML select, would do the same thing - put a bogus entry as the first Option element to your SELECT.

Or, you set the emptyText to 'Select Something..' and don't make it a required field. Either way, you have to pass some default value back to the server to indicate no selection was made.

ben.jones
19 Jun 2007, 1:40 PM
Hi - I am very new to these great controls and the first task I am trying to complete is to build up a combo which will do the following;

1. Display a set of data from a database table (which I will retrieve and populate myself)
2. If the field is optional - add '(None)' as the first item in the list (with a null value)
3. If the field is mandatory - show '(Please select...)' and force the user to select one of the items from the list

(1) is fine, as is (2). However (3) I have been having trouble with. I would like to use the emptyText property as this looks the nicest with the light grey shading and means I don't have the extra 'nullable' value at the top of the list.

However if I set that property and leave my forceSelection property 'true' the empty text is never shown. I want to force the user to make a selection (since the field is mandatory), but I don't want anything selected initially - just a nice message stating they need to select something.

Is there an easy way to do this I am missing here?

tryanDLS
19 Jun 2007, 2:03 PM
Compare your code to the combo example. It shows the emptyText value and it works regardless of whether forceSelection is true or false. (1.1Beta)

ben.jones
19 Jun 2007, 6:47 PM
I have checked the example code but I think my problem is related to the select always defaulting to the first item in the list.

I am developing using JSF + Seam. I have a combo with its value bound to a bean property. This property is null and I would like this to initially render the combo as empty, and thus showing the emptyText value.

However when the combo is rendered, it always automatically selects the first item in the combo list. Therefore I never see the emptyText value.

Any ideas what I am doing wrong here?


<tr>

<td class="grid-col-right">
<label for="ctrId">Country:</label>
</td>

<td class="grid-col-left">

<select id="ctrId" name="ctrId" size="1">
<option value="1">Afghanistan</option>
<option value="2">Albania</option>
<option value="3">Algeria</option>
<option value="4">American Samoa</option>
<option value="5">Andorra</option>
<option value="6">Angola</option>
</select>

<script type="text/javascript">

Ext.onReady( function()
{
var comboBox = new Ext.form.ComboBox(
{
typeAhead: true,
triggerAction: 'all',
transform: 'ctrId',
emptyText: '(Please select...)',
forceSelection: true,
selectOnFocus: true,
resizable: true
});
});

</script>

</td>

</tr>

gnapse
21 Jun 2007, 1:14 PM
Why is this a difficult problem? Load your data from the server. In the load handler, insert an additional row in the store with a key value lower than your lowest value (e.g. 0) and display value of 'None' or whatever you want. If you were building an HTML select, would do the same thing - put a bogus entry as the first Option element to your SELECT.

This would work fine for a particular combo field, but if you do not know the store's recordDef structure in advance you cannot insert that additional row upon load of the data-store. Why wouldn't I know the recordDef structure in advance? Precisely if I am trying to develop a generic combo with these functionality, versatile enough to work with any data store. That's my problem. Currently I have it working the obvious way, but I am repeating soooo much code, and it is boring.


Or, you set the emptyText to 'Select Something..' and don't make it a required field. Either way, you have to pass some default value back to the server to indicate no selection was made.

The empty text does not work, because suppose the user selects an item from the list, but before submitting the form, the user decides to re-select the empty option. Bang! It is not possible, because there is no empty option. The empty text is just that, the text to show when it is empty, and it is in no way equivalent to an empty option.

Other thing I'd like to say is that even if I managed to get the insert-empty-item-after-data-load way discussed above, I think it is fundamentally wrong from a design point of view. We are trying to say the combo box to allow the user to select en item, or to select none. To create a dummy item to behave as the none option is misleading, and you need to handle and modify the data source, which is conceptually not being modified.

Also, suppose you need to use the same data source for two or more widgets. Two combo boxes, but for two different purposes. One will have the empty option but the other one will not. If you use the modify-data-source approach, then you are obliged to use two different data sources that will load the same data twice. The data source is just that, a data source.

taberg
27 Jul 2007, 7:10 AM
bonk :)

i also want this functionality!

i only get a very thin row, if i try to add a record with value &nbsp; it will not be displayed correctly.

/t

DanielD
31 Jul 2007, 9:53 AM
I did this as a quick hack:


var cb = new Ext.form.ComboBox({
typeAhead: true,
triggerAction: 'all',
forceSelection: true,
grow: true,
emptyText: "Please select one..."
});
// display emptyText initially
if(cb.emptyText) {
cb.setRawValue("");
cb.applyEmptyText();
}

This is for when you're not using a store because you're overriding an existing dropdown. It will not work after any other user interaction.

ThorstenSuckow
18 Sep 2007, 12:24 PM
Any news on this subject yet? I'm in desperate need for this functionality...

steffenk
18 Sep 2007, 1:11 PM
i think the easiest way is to insert an empty record in ds after loading.
I tried something but it's not working
ds.insert(0,[['','']]);
maybe someone knows how to do it with correct syntax.

cdomigan
11 Oct 2007, 7:20 PM
i think the easiest way is to insert an empty record in ds after loading.
I tried something but it's not working
ds.insert(0,[['','']]);
maybe someone knows how to do it with correct syntax.

Anybody know how to do this?

fay
12 Oct 2007, 1:50 AM
dsCombo.on('load', function(store, records, options)
{
dsCombo.insert(0, new Ext.data.Record({/* fields */}));
}, this);

The fields should correspond to your reader's.

FritFrut
12 Oct 2007, 2:29 PM
dsCombo.on('load', function(store, records, options)
{
dsCombo.insert(0, new Ext.data.Record({/* fields */}));
}, this);

The fields should correspond to your reader's.

No, there are many problems with this. Data store should be precisely that, a DATA store.

Empty row in this case is not meaningful data, it's here just to add some functionality of the UI. You probably wouldn't add the empty row to your database for this purpose (or, at least, you shouldn't). And, what happens if there's a Grid and the Combobox bound to the same Store? In this case, you are adding code to show empty row for Combo, and then you are adding some more code to hide empty row in Grid.

Or, a different case, you have two Combos bound to the same Store, but one has to show empty row (for example, you want to filter data based on this selection, or leave it unselected to show all), while other must not (for example, you use this Combo to change some required property of your object).

toriaa
18 Oct 2007, 6:31 AM
bonk :)
i only get a very thin row, if i try to add a record with value &nbsp; it will not be displayed correctly.


I'm having this problem as well. My null selection is already handled server-side (by a java bean tag), but the empty row is smaller than the others in the drop-down.

Changing the row to contain "&nbsp;" or " " makes it the proper size, but this workaround causes problems with having a space as the box's initial value (users likely would not think to backspace before typing a selection). For the same reason, I'd rather not give the empty selection any other value, such as "---" or "All".

Is there any way I can get the empty row to appear the same size as the others? I'm fairly new to web dev... perhaps there is some way that I could apply a CSS style to the ComboBox to fix this? Just brainstorming...

FYI, here is some example code and I've attached an image of the resulting drop-down selection.


<select id="my_select" size="1" class="field">
<option value="-1"></option>
<option value="1">ITEM ONE</option>
<option value="2">ITEM TWO</option>
<option value="3">ITEM THREE</option>
</select>
<script type="text/javascript">
Ext.onReady(function(){
var my_combo = new Ext.form.ComboBox({
triggerAction: 'all',
transform:'my_select',
selectOnFocus: true,
minChars: 0
});
});
</script>

jsakalos
18 Oct 2007, 9:55 AM
If you let users to type in the combo (forceSelection:false) then you don't need first null row at all. User can just select any value, backspace/delete it and submit.

First "null" row is useful only if you have forceSelection:true, user cannot type then and you can have "All", "None" or "---" as descriptive text of this null value.

toriaa
19 Oct 2007, 6:09 AM
Thanks for your quick response!

I understand what you're saying about the empty row being unnecessary. I've now removed it server-side, then made sure that forceSelection is false and allowBlank is true (both defaults).

Unfortunately, this is not an appropriate solution, since I'm transforming from an existing HTML select. Because the HTML select automatically selects the first option, the ComboBox now loads with the first row already selected. I want it to initially be empty!

Any ideas on how I can ensure that the ComboBox loads empty (without adding that ugly null row)?

tryanDLS
19 Oct 2007, 7:26 AM
You could call setValue('') after it's created, assuming you don't have an entry with value=''

toriaa
19 Oct 2007, 7:38 AM
You could call setValue('') after it's created, assuming you don't have an entry with value=''

:( No luck! Not just with setting it to '', but setting it to any value - even one that's already an option in the drop-down - with setValue doesn't work for me... maybe it needs to be refreshed somehow?

toriaa
19 Oct 2007, 7:47 AM
Upon further examination, NONE of the public methods work on my combobox!

When I copy the combobox example/demo into my code (or any combobox that has been loaded from a data store) it works fine... but when I use any combobox that has been transformed from an HTML select, suddenly I've lost all my functionality!

tryanDLS
19 Oct 2007, 8:47 AM
Are you using 1.1.1? I just tried adding this to the combos example:

converted.setValue('') and it works in IE6/7 and FF2.

toriaa
22 Oct 2007, 8:16 AM
I think there was something wrong/corrupt in the one particular file that I was trying to use setValue in. You're right, using setValue('') or clearValue() works!

It is, however, still not a great solution to my original problem, which is with having the empty row appear smaller than the others.


First "null" row is useful only if you have forceSelection:true, user cannot type then and you can have "All", "None" or "---" as descriptive text of this null value.

I understand that I can use "ALL" instead of having an empty row in this case (and I do have forceSelection:true in most of my tags), but I would prefer to have the selection be blank, in keeping with the formatting of my HTML selects.

The empty row problem is something that I would like to see fixed in the future.

But at least everything is working OK now! Thanks so much for your help!

ethraza
19 Jun 2009, 6:38 PM
I know this discussion is old and is for 1.x version, but I'm facing this very same problem in ExtJs 2.2.1.

So, here is my override, maybe it works on 1.x too!

This is adding 3 new options to combobox:
blankFirst // If true insert a new field in store on load.
[B]valueFirst [String/Integer] // The value of the new field. Defaults to null.
displayFirst [String] // The display value of the new field. Defaults to "".



// Combobox (ExtJs 2.2.1) blankFirst override
Ext.form.ComboBox.override({
onLoad : function(){
if(!this.hasFocus){
return;
}
if(this.store.getCount() > 0){
//+
if (this.blankFirst && this.store.data.items[0].data[this.valueField] != this.valueFirst||null) {
var n = {};
n[this.valueField] = this.valueFirst||null;
n[this.displayField] = this.displayFirst||'';
this.store.insert(0, new this.store.reader.recordType(n));
}

this.expand();
this.restrictHeight();
if(this.lastQuery == this.allQuery){
if(this.editable){
this.el.dom.select();
}
if(!this.selectByValue(this.value, true)){
this.select(0, true);
}
}else{
this.selectNext();
if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
this.taTask.delay(this.typeAheadDelay);
}
}
}else{
this.onEmptyResults();
}
},

onSelect : function(record, index){
if(this.fireEvent('beforeselect', this, record, index) !== false){
//+
if (this.blankFirst && record.data[this.valueField] == this.valueFirst||null) {
this.setValue(this.getValue());
} else {
this.setValue(record.data[this.valueField || this.displayField]);
}
this.collapse();
this.fireEvent('select', this, record, index);
}
}
});

whdanj
20 Jul 2009, 12:57 PM
Ethraza, thanks a lot for your plugin, it is really helpful!

The only one line i changed is:


onSelect : function(record, index){
if(this.fireEvent('beforeselect', this, record, index) !== false){
//+
if (this.blankFirst && record.data[this.valueField] == this.valueFirst||null) {
//this.setValue(this.getValue());
this.setValue(null); //Fix, I have to setValue to null
} else {
this.setValue(record.data[this.valueField || this.displayField]);
}
this.collapse();
this.fireEvent('select', this, record, index);
}
}



I know this discussion is old and is for 1.x version, but I'm facing this very same problem in ExtJs 2.2.1.

So, here is my override, maybe it works on 1.x too!

This is adding 3 new options to combobox:
blankFirst // If true insert a new field in store on load.
[B]valueFirst [String/Integer] // The value of the new field. Defaults to null.
displayFirst [String] // The display value of the new field. Defaults to "".



// Combobox (ExtJs 2.2.1) blankFirst override
Ext.form.ComboBox.override({
onLoad : function(){
if(!this.hasFocus){
return;
}
if(this.store.getCount() > 0){
//+
if (this.blankFirst && this.store.data.items[0].data[this.valueField] != this.valueFirst||null) {
var n = {};
n[this.valueField] = this.valueFirst||null;
n[this.displayField] = this.displayFirst||'';
this.store.insert(0, new this.store.reader.recordType(n));
}

this.expand();
this.restrictHeight();
if(this.lastQuery == this.allQuery){
if(this.editable){
this.el.dom.select();
}
if(!this.selectByValue(this.value, true)){
this.select(0, true);
}
}else{
this.selectNext();
if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
this.taTask.delay(this.typeAheadDelay);
}
}
}else{
this.onEmptyResults();
}
},

onSelect : function(record, index){
if(this.fireEvent('beforeselect', this, record, index) !== false){
//+
if (this.blankFirst && record.data[this.valueField] == this.valueFirst||null) {
this.setValue(this.getValue());
} else {
this.setValue(record.data[this.valueField || this.displayField]);
}
this.collapse();
this.fireEvent('select', this, record, index);
}
}
});