So I'm trying to create an 'abnormal' combobox using ExtJs 4 and I'm running into a slight issue which I can't figure out how to resolve. I got the basics down with the code that follows. As of right now I am able to get the dropdown to show all the addresses in a proper format and when I click on the proper address it properly shows the 'Street1' value in the input.
Here is what I'm stuck on:
I'm trying to add an initial item to the combobox that basically says something like 'Add New Address' that the user can select. (I'm planning on having this open a modal where the user can input a new address, save it and then have it be displayed back in the combobox, but all of that should be fairly simple) I can't seem to figure out a way of adding just a simple 'Add New Address' and then tracking the value to see if that value is returned to know to make the modal appear or not. I don't want to add it to the store as (I assume) that will add an item in the database and I'd prefer that not happen for the 'Add New Address'.
Any thoughts on how to get that to work? From below you can see that LocationStore is my store and that the general address components apply.
Thank you in advance.
ComboBox Code:
{
xtype: 'combobox',
anchor: '100%',
listConfig: {
emptyText: 'Add New Address - Empty Text',
itemTpl: '<tpl if="Name">{Name}<br /></tpl>'+'<tpl if="Street1">{Street1}<br /></tpl>'+'<tpl if="Street2">{Street2}<br /></tpl>'+'{City}, {StateOrProvince} {PostalCode}'
},
emptyText: 'Add New Location - tester',
fieldLabel: 'Street 1',
name: 'Street1',
allowBlank: false,
blankText: 'Street 1 Required',
displayField: 'Street1',
forceSelection: true,
store: 'LocationStore',
typeAhead: true,
valueField: 'Street1',
valueNotFoundText: 'Add New Location'
},
Thanks to those who pointed me to the right place in the doc, I finally found it!
I managed to achieve what you want by using the tpl, unfortunately I could not find a way to make the keyboard navigation work for the added item. I've looked at the code of Ext.view.BoundListKeyNav, but didn't find any easy solution...
The key was to use tpl instead of itemTpl, and add the markup for the extra item before the for loop:
listConfig: {
tpl: '<div class="my-boundlist-item-menu">Add New Address</div>'
+ '<tpl for=".">'
+ '<div class="x-boundlist-item">' + itemTpl + '</div></tpl>'
,listeners: {
el: {
delegate: '.my-boundlist-item-menu'
,click: function() {
alert('Go go go!');
}
}
}
}
The rest of the code in on jsFiddle.
#rixo see the comments on sencha api:
Config: Ext.form.field.ComboBoxView
ADD VALUE:
Maybe we can use Sencha merge object function...
To put 'add new location' value at the store top:
var newLocation = { 'Street' : 'Add New Location' };
var dataMerged = Ext.Object.merge(newLocation,myStore.getRange());
myStore.loadData(dataMerged);
SORT:
add name config param to your combobox
On controller: (2 ways)
'nameComboView combobox[name=combo]' : {
select : this.function1, // <-- when you select a item
change : this.funciton2 // <-- when the item select are changing
}
Now, on function, compare the value to open modal window or not.
Related
Could you please tell somebody how prevent fires select event on combobox when focus leave ?
I had the same issue in extjs 6.5.2 modern. I was using a combobox with queryMode: 'remote', forceSelection: true, a custom itemTpl and i was choosing an item using the select event. #Jzf's solution didn't worked for me (i used the change event too) so i had to suspend the select event on focusleave and resume it on focusenter.
That's not a very clean workaround but it does the job for my case.
Here is the full code for my combobox:
{
xtype: 'combobox',
store: Ext.create('demo.store.search.SearchComboStore'),
valueField: 'id',
displayField: 'name',
queryMode: 'remote',
queryParam: 'name',
triggerAction: 'all',
allQuery: '',
minChars: 1,
forceSelection: true,
matchFieldWidth: false,
//[modern] added floated picker config here in order to set the minWidth property for the floated picker
floatedPicker: {
minWidth: (Ext.getBody().getWidth() / 2)
},
itemTpl:
'<div class="ucResultsTable" style="width:' + (Ext.getBody().getWidth() / 2) + 'px">' +
'<div class="ucResultsTableCell" style="width:15%"><b>{value1}</b></div>' +
'<div class="ucResultsTableCell" style="width:15%">{value2}</div>' +
'<div class="ucResultsTableCell" style="width:15%">{value3}</div>' +
'<div class="ucResultsTableCell" style="width:15%">{value4}</div>' +
'<div class="ucResultsTableCell" style="width:15%">{value5}</div>' +
'</div>',
listeners: {
select: function (comboBox, records, eOpts) {
var container = comboBox.up('app-container-panel');
container.fireEvent('selectComboItem', container, records.data);
},
//<Workaround>
//blur/focusleave is firing select event
//and changes the record selection
focusleave: function (comboBox) {
comboBox.suspendEvent('select');
},
focusenter: function (comboBox) {
comboBox.resumeEvent('select');
}
//</Workaround>
}
}
The problem occurs because the combo forces the selection, even when the user hasn't actually selected another value.
There are a couple of ways to workaround this issue.
Use the select listener without forceSelection
Use the change listener with forceSelection
Both ways, the user will have to choose an item from the combo list (which is, probably, why you used the forceSelection config in the first place).
Test the workaround in fiddle
THis is a bug
Correspond theme on Sencha Forum
I have in my ExtJS 4.2.1 Application a grid with the following editable column:
text: 'Location',
dataIndex: 'LocationId',
width: 140,
renderer: function(value) {
var record = me.store.findRecord('LocationId', value);
return record.get('Description');
},
editor: {
xtype: 'combobox',
typeAhead: true,
triggerAction: 'all',
store: Ext.create('App.store.catalog.Location', {
autoLoad: true
}),
displayField: 'Description',
valueField: 'LocationId',
listConfig: {
width: 250,
loadingText: 'Searching...',
// Custom rendering template for each item
getInnerTpl: function() {
return '<b>{Code}</b><br/>(<span style="font-size:0.8em;">{Description}</span>)';
}
}
}
The combo has a renderer to display the Description of the LocationId selected.
Then, my grid has the feature 'Ext.grid.plugin.CellEditing' so I can edit just that column cell.
The problem that I have is when I press the "Update" button, the combo display value returns to the original it used to have, even if the LocationId in the record has the right value.
This is my code that gets fired when the user press the "Update" button.
me.rowEditing = Ext.create('Ext.grid.plugin.RowEditing', {
clicksToMoveEditor: 1,
autoCancel: false,
listeners: {
edit: function(editor, e) {
var record = e.record;
me.setLoading('Updating...');
App.util.Ajax.request({
noMask: true,
url: '/api/catalog/UpdateEmployeeLocation',
jsonData: record.getData(),
success: function(response, opts) {
var obj = Ext.decode(response.responseText);
if (obj.success) {
// commit changes (no save just clear the dirty icon)
me.getStore().commitChanges();
}
},
callback: function() {
me.setLoading(false);
}
});
}
}
});
The record is saved correctly in my database but the combo display value is not updated with the description that corresponds to the LocationId. If I reload the store from server again then It shows correctly.
So, there is something wrong with the renderer in my column that is not updating the value after I update my record.
Any clue on how to get around this?
Thanks.
You are setting dataIndex as 'LocationId' but no where you are changing the 'LocationId', you are just changing description and updating it in rendered method. Since there no change in 'LocationId', store doesn't consider it as dirty field and hence rendered function is not getting called. One quick and dirty way could be instead of using 'LocationId', create another field in the model say 'LocationIdchangeTraker'. Use 'LocationIdchangeTraker' instead of 'LocationId' in data index. It doesn't not effect your view because you are changing the value in reneerer function. Now whenever you update the function change the value of 'LocationIdchangeTraker' as shown below.
record.set('LocationIdchangeTraker',Ext.getId());
I am using extJs 3.4 combobox autocomplete, i want autocomplete search to work interchangeably of characters position.
For example when i type 'v' it autocompletes to vanessa (it is working well) but when i type 'a' it doesnt autocomplete.
i would like to autocomplete by any character(that exist) in any site.
Something like this
a - vanessa,daniela
s - vanessa
or ssa - vanessa
This is my code
xtype: 'combo',
fieldLabel: 'prov',
id : 'lang',
store:[['tr','vanessa'],['ru','daniela'],['en','English']],
mode: 'local',
triggerAction: 'all',
selectOnFocus:true,
listeners: {
afterrender: function(combo) {
var recordSelected = combo.getStore().getAt(1);
combo.setValue(recordSelected.get('field1'));
}
}
Thank you and i apologize for my grammar it isn't very good.
You have to somewhat change the behaviour of the doQuery method. As you see in the code, we're lucky because there's an event giving us the opportunity to do that without hacking the combo too much :) Furthermore, if we pass a regex to the store's filter method, it will ignore its other arguments (the one we would have wanted to pass is anyMatch... but the combo doesn't give us the opportunity).
So, we just have to hook on this event and transform the query string property into a regex! Here's how:
Ext.create({
xtype: 'combo',
renderTo: Ext.getBody(),
fieldLabel: 'prov',
id: 'lang',
store: [
['tr', 'vanessa'],
['ru', 'daniela'],
['en', 'English']
],
mode: 'local',
triggerAction: 'all',
selectOnFocus: true,
listeners: {
beforequery: function(q) {
// we don't want to crash if there's nothing in there
if (q.query) {
// we need the length later in the doQuery function,
// for respecting minChars
var length = q.query.length;
q.query = new RegExp(Ext.escapeRe(q.query));
// pretend I am a string, eh eh
q.query.length = length;
}
}
}
});
You may want to override the Ext.form.ComboBox class to add this as an option (I would call it anyMatch) since that's a pretty common requirement.
I have a combo box which populates its values based on the selection of another combobox.
I have seen examples where the params in the underlying store are changed based on the selection, but what I want to achieve is to change the store itself of the second combo based on the selection on the first combo. This is my code, but it doesn't work. Can someone please help?
{
xtype: 'combo',
id: 'leads_filter_by',
width: 100,
mode: 'local',
store: ['Status','Source'],
//typeAhead: true,
triggerAction: 'all',
selectOnFocus:true,
typeAhead: false,
editable: false,
value:'Status',
listeners:{
'select': function(combo,value,index){
var filter_to_select = Ext.getCmp('cmbLeadsFilter');
var container = filter_to_select.container;
if (index == 0){
filter_to_select.store=leadStatusStore;
filter_to_select.displayField='leadStatusName';
filter_to_select.valueField='leadStatusId';
} else if(index==1) {
filter_to_select.store=leadSourceStore;
filter_to_select.displayField='leadSourceName';
filter_to_select.valueField='leadSourceId';
}
}
}
},
{
xtype: 'combo',
id: 'cmbLeadsFilter',
width:100,
store: leadStatusStore,
displayField: 'leadStatusName',
valueField: 'leadStatusId',
mode: 'local',
triggerAction: 'all',
selectOnFocus:true,
typeAhead: false,
editable: false
},
That is not how its designed to work!! When you set a store in the config, you are binding a store to the combo. You don't change the store, instead you are supposed to change the data when required.
The right way of doing it would be to load the store with correct data from the server. To fetch data, you can pass params that will help the server side code get the set of options you need to load.
You will not want to change the store being used... Simply put, the store is bound to the control as it is instantiated. You can, however, change the URL, and params/baseParams used in any additional POST requests.
Using these params, you can code your service to return different sets of data in your combo box's store.
For the proposed problem you can try below solution :
Use below "listener" snippet for the first "leads_filter_by" combo. It will handle the dynamic store binding / changing for the second combobox.
listeners:{
'select': function(combo,value,index){
var filter_to_select = Ext.getCmp('cmbLeadsFilter');
var container = filter_to_select.container;
if (index == 0){
//filter_to_select.store=leadStatusStore;
filter_to_select.bindStore(leadStatusStore);
filter_to_select.displayField='leadStatusName';
filter_to_select.valueField='leadStatusId';
} else if(index==1) {
//filter_to_select.store=leadSourceStore;
filter_to_select.bindStore(leadSourceStore);
filter_to_select.displayField='leadSourceName';
filter_to_select.valueField='leadSourceId';
}
}
}
Hope this solution will help you.
Thanks & Regards.
I had a similar problem. The second combobox would load the store and display the values, but when I would select a value, it would not actually select. I would click the list item and the combobox value would remain blank.
My research also suggested that it was not recommended to change the store and field mappings on a combobox after initialization so here was my solution:
Create a container in the view that would hold the combobox to give me a reference point to add it back later
Grab a copy of the initial config off of the combobox ( this lets me set my config declaritively in the view and not hard code it into my replace function ... in case I want to add other config properties later)
Apply new store, valueField and displayField to that config
Destroy old combobox
Create new combobox with modified config
Using my reference from step 1, add the new combobox
view:
items: [{
xtype: 'combobox',
name: 'type',
allowBlank: false,
listeners: [{change: 'onTypeCombo'}],
reference: 'typeCombo'
}, { // see controller onTypeCombo for reason this container is necessary.
xtype: 'container',
reference: 'valueComboContainer',
items: [{
xtype: 'combobox',
name: 'value',
allowBlank: false,
forceSelection: true,
reference: 'valueCombo'
}]
}, {
xtype: 'button',
text: 'X',
tooltip: 'Remove this filter',
handler: 'onDeleteButton'
}]
controller:
replaceValueComboBox: function() {
var me = this;
var typeComboSelection = me.lookupReference('typeCombo').selection;
var valueStore = Ext.getStore(typeComboSelection.get('valueStore'));
var config = me.lookupReference('valueCombo').getInitialConfig();
/* These are things that get added along the way that we may also want to purge, but no problems now:
delete config.$initParent;
delete config.childEls;
delete config.publishes;
delete config.triggers;
delete config.twoWayBindable;
*/
config.store = valueStore;
config.valueField = typeComboSelection.get('valueField');
config.displayField = typeComboSelection.get('displayField');
me.lookupReference('valueCombo').destroy();
var vc = Ext.create('Ext.form.field.ComboBox', config);
me.lookupReference('valueComboContainer').add(vc);
},
Can someone tell me how to get rid of the feature that filters combo box items.
when i click on the trigger of the combo, i want to display ALL menu items regardless of what text is already in the box, NOT filtered. I've tried several different config options with no luck.
make sense ?
for example, if i have 'View' as my text in the combo, and i click on the trigger, it will only show 'View1' and 'View2' items, i want it to include all the others...
Thanks!
heres my current config
{
...
items: [{
xtype: 'combo',
id: 'myViewsCombo',
emptyText: 'Select View',
selectOnFocus: true,
listeners: {
select: function(combo, record, index) {
L3.handlers.loadView(combo.value);
}},
store: ['View1', 'View2','blahblah']
}]
}
Setting triggerAction: "all" solved the same problem for me.
Try the setting the 'disableKeyFilter' config option to true.
See the ext combobox api.