PDA

View Full Version : data store and key value pairs for combo box



stimpy
13 Jun 2012, 5:45 PM
I am using 4.1 and have a store setup with a proxy to retrieve records .

the data i am getting looks like this


[[4,"myValue1"],[56,"myValue2"],[33,"myValue3"]]

I can get my store to load this data but I want to use the loaded data for combo box valueField and Display field.

Is there a way to do this ? How do configure my store so that the key, value pairs are read correctly?

sword-it
13 Jun 2012, 9:55 PM
Hi stimpy,

Give "fields : ['value', 'display']" config to your store, and give same fields value to displayField and valueField config of combobox for example -


xtype: 'combo'
, forceSelection: true
, hiddenName: 'cat_id'
, store: new Ext.data.ArrayStore({
url: 'xxxxxxx'
, root: 'Root'
, fields: ['id', 'n']
})
, displayField: 'n'
, valueField: 'id'


for more information read http://docs.sencha.com/ext-js/4-1/#!/api/Ext.data.Store-cfg-fields

stimpy
14 Jun 2012, 4:04 AM
Sword thanks for the suggestions

However the combobox is still not working. Selecting the combobox gets a menu frame which fits the data but is empty. The store contains the right number of items however . It appears the display values are not being displayed.

config as follows


xtype:'combobox',
name:'myComboBox',
store:myTestStore,
displayField:'n',
valueField:'id',
queryMode:'remote'

store

Ext.create('Ext.data.JsonStore',{
autoload:true,
fields['id','n'],
proxy:{
type:'ajax',
url:'xxxxx',
reader:{
type:'json',
root:'rows'
}
}
});

stimpy
14 Jun 2012, 7:28 AM
I also tested the submit of this setup . While the combo box appears to be the right height and width for the data it does not actually appear to populate with the data( display or value ) .

Viewing the the raw items on the store however each have the correct data . Something about the mapping from store to combo box is not right ?

Examining myTestStore.data.items[0] I see it has 2 fields with keys "id" and "n" and the raw shows two values of 4 and "myValue1" .

This appears to line up ? Anyone have a suggestion ? This seems awfully difficult to get a list of key value pairs working .

sword-it
14 Jun 2012, 10:36 PM
"autoload" is not correct config in store class it's "autoLoad" and try to give one more config (triggerAction : 'all') to your combobox.

stimpy
15 Jun 2012, 3:39 AM
autoLoad was a typo here in the forums. I added triggerAction : 'all' to the combobox.

No change still nothing in the combo box but the store has items.

Strangely there are also no errors being thrown . If the combo box cannot parse the store I would expect some sort of error .

stimpy
15 Jun 2012, 11:18 AM
OK to test this further I created a new store and data set



var myTestData=[[33,"value1"],[61,"value2"],[47,"value3"]];

var mySmallTestStore = Ext.create('Ext.data.JsonStore',{
autoLoad=true,
fields:['id,'n']
data:myTestData
});


I can change my storename in the combobox config and it loads correctly.

So something is wrong when the data is loaded in from the reader

c5m7b4
15 Jun 2012, 1:54 PM
Hey,
I remember having this problem before but I cant for the life of me remember what it was. By chance do you have the data of that combobox being driven by a choice selection from another combox?

stimpy
15 Jun 2012, 3:44 PM
Yes ! thats exactly what I am doing

The selection of combo box A called a setProxyUrl and reload on combo B which I posted earlier seems to work correctly when the data is preset.

The data appears to be there but the combo box is not working correctly.

c5m7b4
16 Jun 2012, 9:22 AM
Thats it I think. Its a bug in Ext JS from what I remember. Here is the link to what I posted just so you can make sure that you have the same problem:

MyPost
http://www.sencha.com/forum/showthread.php?184207-Controlling-one-combobox-by-selection-of-another-combobox&p=745987#post745987 (http://www.sencha.com/forum/showthread.php?184207-Controlling-one-combobox-by-selection-of-another-combobox&p=745987#post745987)

Here is where I was directed to
http://www.sencha.com/forum/showthread.php?152324

H (http://www.sencha.com/forum/showthread.php?152324)ope this helps. I put that little code snippet at the top of my form to modify the combobox and it worked like a champ. Here is the code snippet that I added to my js file:


Ext.override(Ext.form.field.ComboBox, {
createPicker: function() {
var me = this,
picker,
menuCls = Ext.baseCSSPrefix + 'menu',
opts = Ext.apply({
pickerField: me,
selModel: {
mode: me.multiSelect ? 'SIMPLE' : 'SINGLE'
},
floating: true,
hidden: true,
ownerCt: me.ownerCt,
cls: me.el.up('.' + menuCls) ? menuCls : '',
store: me.store,
displayField: me.displayField,
focusOnToFront: false,
pageSize: me.pageSize,
tpl: me.tpl,
loadMask: me.queryMode === 'local' ? false: true
}, me.listConfig, me.defaultListConfig);


picker = me.picker = Ext.create('Ext.view.BoundList', opts);
if (me.pageSize) {
picker.pagingToolbar.on('beforechange', me.onPageChange, me);
}


me.mon(picker, {
itemclick: me.onItemClick,
refresh: me.onListRefresh,
scope: me
});


me.mon(picker.getSelectionModel(), {
'beforeselect': me.onBeforeSelect,
'beforedeselect': me.onBeforeDeselect,
'selectionchange': me.onListSelectionChange,
scope: me
});


return picker;
}
});

stimpy
17 Jun 2012, 8:14 AM
Thanks for the post.

I will work thru these and get back .

stimpy
18 Jun 2012, 6:03 AM
No luck

As far as I can see the "loaded store" does not actaully parse the array out correctly.
This appears to be a bug as json arrays are parsed correctly elsewhere ?

In your case you were using JSON objects in mine its a JSON array .

I pared down my test code to this


//stores and test data
varMyTestData=[[33,"value1"],[61,"value2"],[47,"value3"]];

var myTestStaticStore =Ext.create('Ext.data.JsonStore',{
fields:['id,'n']
data:myTestData
});

//where get on the url myController/myMethod returns [[33,"value1"],[61,"value2"],[47,"value3"]]

var myTestAjaxStore =Ext.create('Ext.data.JsonStore',{
fields:['id,'n']
proxy:{
type:'ajax';
url:'myController/myMethod'
}
});

//comboBox works fine with static store

xtype:'combobox',
name:'myComboBox',
store:myTestStaticStore ,
displayField:'n',
valueField:'id',
queryMode:'local'

//combo box fails with loaded store

xtype:'combobox',
name:'myComboBox',
store:myTestAjaxStore,
displayField:'n',
valueField:'id',
queryMode:'local'

//which is loaded from another combobox using this

xtype:'combobox',
name:'mySettingComboBox',
store: [[1, 'Single Store'], [2, 'Group'], [3, 'Sub-Group']],
listeners:{
change: function(combo, value) {
console.log('load records called');
myTestAjaxStore.load();
} }

stimpy
19 Jun 2012, 3:24 AM
The workaround for this problem is to create an ArrayStore if populating via a proxy.

like this




var myTestAjaxStore =Ext.create('Ext.data.ArrayStore',{
fields:['id,'n'],
proxy:{
type:'ajax',
url:'myController/myMethod',
reader:{
type:'array'
}
}
});



no clue why this is required

uriel_online
10 Jul 2012, 3:49 PM
This override for ExtJS 4.1 should do


Ext.define('Panax.form.field.ComboBox', {
override: 'Ext.form.field.ComboBox',
constructor: function (config) {
this.callParent(arguments);
},
anyMatch: true,
caseSensitive: false,
findRecordByValue: function(value) {
return this.findRecord(this.valueField, Ext.isObject(value)?value[this.valueField]:value);
},
findRecordByDisplay: function(value) {
return this.findRecord(this.displayField, Ext.isObject(value)?value[this.displayField]:value);
},

setValue: function(value, doSelect) {
var me = this,
valueNotFoundText = me.valueNotFoundText,
inputEl = me.inputEl,
i, len, record,
dataObj,
matchedRecords = [],
displayTplData = [],
processedValue = [];
if (me.store.loading) {
// Called while the Store is loading. Ensure it is processed by the onLoad method.
me.value = value;
me.setHiddenValue(me.value);
return me;
}
// This method processes multi-values, so ensure value is an array.
value = Ext.Array.from(value);
// Loop through values, matching each from the Store, and collecting matched records
for (i = 0, len = value.length; i < len; i++) {
record = value[i];
if (!record || !record.isModel) {
record = me.findRecordByValue(record);
}
// record found, select it.
if (record) {
matchedRecords.push(record);
displayTplData.push(record.data);
processedValue.push(record.get(me.valueField));
}
// record was not found, this could happen because
// store is not loaded or they set a value not in the store
else {
// If we are allowing insertion of values not represented in the Store, then push the value and
// create a fake record data object to push as a display value for use by the displayTpl
if (!me.forceSelection) {
processedValue.push(Ext.isObject(value[i])?value[i][this.valueField]:value[i]);
dataObj = {};
dataObj[me.displayField] = Ext.isObject(value[i])?value[i][this.displayField]:value[i];
displayTplData.push(dataObj);
// TODO: Add config to create new records on selection of a value that has no match in the Store
}
// Else, if valueNotFoundText is defined, display it, otherwise display nothing for this value
else if (Ext.isDefined(valueNotFoundText)) {
displayTplData.push(valueNotFoundText);
}
}
}
// Set the value of this field. If we are multiselecting, then that is an array.
me.setHiddenValue(processedValue);
me.value = me.multiSelect ? processedValue : processedValue[0];
if (!Ext.isDefined(me.value)) {
me.value = null;
}
me.displayTplData = displayTplData; //store for getDisplayValue method
me.lastSelection = me.valueModels = matchedRecords;
if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
inputEl.removeCls(me.emptyCls);
}
// Calculate raw value from the collection of Model data
me.setRawValue(me.getDisplayValue());
me.checkChange();
if (doSelect !== false) {
me.syncSelection();
}
me.applyEmptyText();
return me;
},
doQuery: function(queryString, forceAll, rawQuery) {
queryString = queryString || '';
// store in object and pass by reference in 'beforequery'
// so that client code can modify values.
var me = this,
qe = {
query: queryString,
forceAll: forceAll,
combo: me,
cancel: false
},
store = me.store,
isLocalMode = me.queryMode === 'local',
needsRefresh;
if (me.fireEvent('beforequery', qe) === false || qe.cancel) {
return false;
}
// get back out possibly modified values
queryString = qe.query;
forceAll = qe.forceAll;
// query permitted to run
if (forceAll || (queryString.length >= me.minChars)) {
// expand before starting query so LoadMask can position itself correctly
me.expand();
// make sure they aren't querying the same thing
if (!me.queryCaching || me.lastQuery !== queryString) {
me.lastQuery = queryString;
if (isLocalMode) {
// forceAll means no filtering - show whole dataset.
store.suspendEvents();
needsRefresh = me.clearFilter();
if (queryString || !forceAll) {
me.activeFilter = new Ext.util.Filter({
root: 'data',
property: me.displayField,
value: queryString,
anyMatch: me.anyMatch,
caseSensitive: me.caseSensitive
});
store.filter(me.activeFilter);
needsRefresh = true;
} else {
delete me.activeFilter;
}
store.resumeEvents();
if (me.rendered && needsRefresh) {
me.getPicker().refresh();
}
} else {
// Set flag for onLoad handling to know how the Store was loaded
me.rawQuery = rawQuery;
// In queryMode: 'remote', we assume Store filters are added by the developer as remote filters,
// and these are automatically passed as params with every load call, so we do *not* call clearFilter.
if (me.pageSize) {
// if we're paging, we've changed the query so start at page 1.
me.loadPage(1);
} else {
store.load({
params: me.getParams(queryString)
});
}
}
}
// Clear current selection if it does not match the current value in the field
if (me.getRawValue() !== me.getDisplayValue()) {
me.ignoreSelection++;
me.picker.getSelectionModel().deselectAll();
me.ignoreSelection--;
}
if (isLocalMode) {
me.doAutoSelect();
}
if (me.typeAhead) {
me.doTypeAhead();
}
}
return true;
}
});


Notice that doQuery config is also overriden to allow anyMatch and caseSensitive configs to work, this part can be dismissed.

It works for both remote and local stores, now you can set values in the form of a value, a literal object, or an array of both (of the same type as in your store).

thus, your code:

[[4,"myValue1"],[56,"myValue2"],[33,"myValue3"]]

should be an array of literal objects instead:

[{id:4, text:"myValue1"},{id:56,text:"myValue2"},{id:33,text:"myValue3"}]
this will load your combo with all of these values even if the store is not loaded but validated once it is

Be aware that for remote loading of literal objects to work valueField and displayField should be set on the combobox and forceSelection be initially set to false (you can enable it later)

Any comments or corrections are welcome.

Greetings