ExtJS: Combobox after reload store dont set value - combobox

I think I have a very popular problem, but not found answer for it now. :)
I got 2 similar comboboxes - at first i set my value by id - comboT.setValue("22763"); and it properly set a text value linked with this id.
At second combobox i at first reload store(jsonstore) and then set value - comboC.setValue("3"); But this combo set only ID not text value (if i open list i can see what combo properly marked text value. And after (if list simply close without select) text value properly displayed at combo.
How to solve this problem?
Thanks.

Something like this, syntax may be slightly off since I am doing it from memory:
var val = 3;
var store = comboC.getStore();
store.on("load", function() {
comboC.setValue(val);
}):
store.load();

Loading the store is asynchronous, you might want to move setting the new value into the callback: event handler of store.load({...}), because otherwise, you set the value before the store is actually loaded.
EDIT: for completeness, an example, so you have an alternative version (in some cases it might be undesireable to bind the callback to the store itself, like ormuriauga did):
var val = 3;
var store = comboC.getStore();
store.load({
callback: function() {
comboC.setValue(val);
}
});

One more example on how to set the combobox's value by searching a string in the underlying data store. I was able to code this by using the samples in these answers as a baseline:
//The store's data definition must have at least a data.id field defined
set_combobox_value_from_store = function (combobox, valueField, value) {
//Get a reference to the combobox's underlying store
var store = combobox.getStore();
store.load({
callback: function () {
//Find item index in store
var index = store.find(valueField, value, false);
if (index < 0) return;
//Get model data id
var dataId = store.getAt(index).data.Id;
//Set combobox value and fire OnSelect event
combobox.setValueAndFireSelect(dataId);
}
});

In extjs 4.1 looks like combo.setValue() works when the type of valueField in the Model is "string". this was my code
Ext.define('Model.CboObras', {
extend: 'Ext.data.Model',
idProperty: 'co_obra',
fields: [{
name: 'co_obra',
type: 'int'
}, {
name: 'nb_obra',
type: 'string'
}]
});
this does not work.
When I changed my code to this:
Ext.define('Model.CboObras', {
extend: 'Ext.data.Model',
idProperty: 'co_obra',
fields: [{
name: 'co_obra',
type: 'string'
}, {
name: 'nb_obra',
type: 'string'
}]
});
After that I use this:
var store = comboC.getStore();
store.load({
callback: function() {
comboC.setValue(val);
}
});
it now works like a charm!

Related

How do you create dynamic local store based on record property

I have an integer field on backend. This field is an offset (CPI Index delay) that could takes values from 0 -> N. On frontend I want to display a combo box with this value / label:
{key: 0, label: "0 - 21/06/2020"}
{key: 1, label: "1 - 21/06/2021"}
{key: 2, label: "2 - 21/06/2022"}
{key: 3, label: "3 - ... "}
The number of option is calculated this way: rent_end_date.year - first_due_date.year. Each time the first_due_date change, the options of the combo box must be calculated again.
To achieve this I've initialed a variabile indexOffsetChoices with relative formula to calculate choices each time a first_due_date changes:
viewModel: {
type: 'rentsdetailformmodel',
data: {
hideRentsDetailGrids: false,
indexOffsetChoices: []
},
formulas: {
calculateIndexOffsetChoices: {
bind: '{detailRecord.first_due_date}',
get: function (firstDueDate) {
var detailRecord = this.get('detailRecord'),
indexOffset = detailRecord.get('index_offset'),
rentEndDate = detailRecord.get('end_date');
if (indexOffset !== undefined && rentEndDate !== undefined) {
var choices = [];
for (i = 0; i < (rentEndDate.getFullYear() - firstDueDate.getFullYear()); i++) {
var RawCPIDate = new Date(firstDueDate.setFullYear(firstDueDate.getFullYear() + i)),
CPIDateFmt = Ext.Date.format(new Date(RawCPIDate), 'd/m/Y'),
label = i + ' - ' + CPIDateFmt;
choices.push({"key": i, "label": label});
}
this.indexOffsetChoices = choices;
}
}
}
}
},
Then I added my combo box with an inline local store that point to the viewModel variable indexOffsetChoices:
items: [{
xtype: 'combobox',
name: 'index_offset',
reference: 'index_offset',
fieldLabel: 'CPI Application Delay',
valueField: 'key',
displayField: 'label',
queryMode: 'local',
bind: '{detailRecord.index_offset}',
store: {
type: 'store',
storeId: 'rent__index_offset',
idProperty: 'key',
fields: ['key', 'label'],
data: this.indexOffsetChoices
}
}]
But the data are not loaded. This is the right approach? How do you create local store based on records / dynamic data? What I'm missing?
You did the hardest way sir! The 'data' property in viewModel is actually not used to store large of array data except you will work hard to modify them.
Setting dynamic options in combobox can be achieved by updating (or re-setting) it's options (using yourcombofield.setOptions([/*new array data*/]) like here ) or it's data store (using yourcombofield.getStore().setData([/* new array data*/]) like here) or if you declare your store in viewModel 'stores' property like here and have linked to your combobox's store property, you don't need to access combobox again, just modify the array data of the store and your combobox's options which has been linked to the store will be updated automatically. The important thing, try to give the easiest way to modify you array data inside the store.
Now, let's talk about when and where will you place your code to update this combobox's data? This is about the event's owner which you want to listen (and also affects your case). You said "Each time the first_due_date change". If first_due_date is affected by another field, just put your code inside it's change/keyup/keydown listeners and then re-treat you data by filtering,removing,adding, etc and the last, update the old data with the new data where ever the data has been stored before.

State provider does not restore sorters properly

I'm trying to store my grid state using the Ext.state.CookieProvider. The problem is I can't restore sorters parameters while state itself (width, order) is restoring properly.
First I've created cookieprovider in init() method of the viewport viewcontroller:
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider', {}));
My store is set to auto load with remote sorting:
Ext.define('MyApp.requests.store.QueryRequestsGridStore', {
extend: 'Ext.data.Store',
model: 'MyApp.requests.model.QueryRequestsGridModel',
alias: 'store.queryRequestsGrid',
remoteSort: true,
autoLoad: true,
proxy: {
startParam: 'offset',
limitParam: 'limit',
url: '/requests',
noCache: false,
type: 'ajax',
reader: {
type: 'json',
rootProperty: 'data',
totalProperty: 'total'
}
},
});
Store is defined in grid using viewmodel binds:
bind: {
store: '{queryRequestsGrid}'
},
I'm loading the grid containing store from the viewport viewcontroller on button click like this:
var panelToAddName = Ext.create('MyApp.requests.view.QueryRequestsGridView', {});
var mainViewPort = Ext.ComponentQuery.query('#mainViewPort')[0];
var regionPanel = mainViewPort.down('[region=center][xtype=panel]');
regionPanel.removeAll();
regionPanel.add(panel);
Cookie contains sorters, but grid is loaded without any sort parameters.
"storeState":{"sorters":[{"root":"data","property":"date_completed","direction":"ASC"}]}}}
I've dug into the ext-all-debug.js source file and found initState() method of a 'Ext.state.Stateful' class.
initState: function() {
var me = this,
id = me.stateful && me.getStateId(),
hasListeners = me.hasListeners,
state, combinedState, i, len, plugins, plugin, pluginType;
if (id) {
combinedState = Ext.state.Manager.get(id);
if (combinedState) {
state = Ext.apply({}, combinedState);
if (!hasListeners.beforestaterestore || me.fireEvent('beforestaterestore', me, combinedState) !== false) {
plugins = me.getPlugins() || [];
for (i = 0 , len = plugins.length; i < len; i++) {
plugin = plugins[i];
if (plugin) {
pluginType = plugin.ptype;
if (plugin.applyState) {
plugin.applyState(state[pluginType], combinedState);
}
delete state[pluginType];
}
}
me.applyState(state);
if (hasListeners.staterestore) {
me.fireEvent('staterestore', me, combinedState);
}
}
}
}
},
If to log me.store from inside of this method, the store is shown in console as ext-empty-store while me is my loaded grid. Seems like state is applying before the store is properly loaded.
If to reuse the initState method inside beforerender grid event, sorters are restoring from cookie properly.
Any suggestions?
I have not worked with viewmodel binds as the sole bind between store and grid, and can't comment on whether that is supposed to work at all, or just by accident.
But I know that the viewmodel is processed very late, because the view has to be fully initialized first (including applyState), so the viewmodel can find all the components it wants to bind the listeners to.
So please try to add the store using any of the two "old-school" methods that work even without the viewmodel: store:'MyStoreId' or store:Ext.create('MyApp.store.MyStore') on the grid. That way, the store should be bound to the grid before applyState.
Furthermore, I see another issue you should address: Your store loads directly after store init. (autoLoad:true). At that time, it is not yet bound to the grid; thus, no sort/filter has been applied, which means that with remoteSort/remoteFilter enabled, you are sending too many requests to the server. I would recommend to load the store only after it has been applied to the grid (in grid.initComponent after the callParent call, or from grid.boxready listener). If you really want to use autoLoad, I'd recommend to look into setAutoLoad method

Values not being added to combobox dynamically

I have a combobox whose values I need to populate via the json formatted string I am retrieving via AJAX call.
Here's the string which I have retrieved (stored in data)
{
"a2m":
[
"a2mMeeting",
"sugar"
]
}
The combobox must contain a2m (this is the only name in the string as of now)
Here's what I have been trying:
Approach 1:
this.initAjaxCall = Ext.Ajax.request({
url : 'indigo/restproxy/get/v1/applications/list',
method:'GET',
scope : this,
success : function(result, request) {
var data = Ext.decode(result.responseText);
Object.keys(data).forEach(function(key) {
console.log(key);
Ext.getCmp('appCombo').getStore().add({appName : key});
})
}
});
this.appcombo = Ext.create('Ext.form.field.ComboBox', {
id : 'appCombo',
store: this.appStore
});
this.appStore = Ext.create('Ext.data.Store', {
fields : [
{
name : 'appName',
type : 'string'
}
]
});
Approach 2:
this.appStore = Ext.create('Ext.data.Store', {
fields: ['appName'],
proxy: {
type: 'ajax',
url: 'indigo/restproxy/get/v1/applications/list',
method : 'GET'
},
listeners: {
load: function(store, records, successful, eOpts ) {
store.insert(0, {
'appName' : 'yellow' //Trying to populate randomly using this method.
})
}
}
})
this.appcombo = Ext.create('Ext.form.field.ComboBox', {
id : 'appCombo',
store: this.appStore
});
In both the cases the combobox doesn't load any value and I am unable to see any value in the dropdown menu.
EDIT 1: When I printed the store.getCount() in the console after adding one element, the value is shown as 1 (checked by adding two elements and it does show 2). This implies the values are being added to the store but not being shown in the combobox dropdown menu. Kindly suggest how to resolve this.
SOLUTION:
The solution as it turns out was by adding a statement queryMode : 'local'. I don't understand why this was creating an issue. Anyone willing to shed light on this is welcome to do so.
As you have proven the store is being populated. However you haven't set a display field on the combo box.
this.appcombo = Ext.create('Ext.form.field.ComboBox', {
id : 'appCombo',
store: this.appStore,
displayField: 'appName'
});
displayField: The underlying data field name to bind to this ComboBox. Defaults to: 'text'
valueField: The underlying data value name to bind to this ComboBox. Defaults to match the value of the displayField config.

How to set the Id field of an ArrayStore (So that records can be looked up by the value of that field) in ExtJS 3

I am having trouble with Ext.data.ArrayStore. I have one defined as so:
var store = new Ext.data.ArrayStore({
fields: [
'myIdField',
'myDataField'
],
idProperty: 'myIdField'
});
store.add(new store.recordType({
myIdField: 'a',
myDataField: 'SomeData'
}));
However, when I do
var myInsertedRecord = store.getById('a');
the value of myInsertedRecord is 'undefined'.
Am I misunderstanding how does the setting o the record id work?
http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.data.ArrayStore does not have an idProperty.
Try creating a Model, specifying the idProperty in the Model. Use that model to create your store.
Example:
Ext.define('MyData', {
extend: 'Ext.data.Model',
fields: ['myIdField', 'myDataField'],
idProperty: 'myIdField'
});
var store = Ext.create('Ext.data.ArrayStore', {
model: 'MyData'
});
store.add({
myIdField: 'a',
myDataField: 'SomeData'
});
var myRecord = store.getById('a');
I know this is an old thread, but I'll answer it anyway ...
The issue is the way you are creating the new record to add to the store. Have a look at the Ext.data.Record-static-method-create function. You will see that it can take an optional ID parameter.
So, to make your above example work, you'll need to add the record to the store like so:
store.add(new store.recordType({
myIdField: 'a',
myDataField: 'SomeData'}, 'a'));
Notice the last 'a', that's where you apply the ID to the record.
After that, your added record will have an ID so store.getById('a') will work for you.

show dynamic data using checkbox in extjs

I have a combo box in which the user selects a value, that value is passed to the checkbox data store and it is populated dynamically from database (oracle). I tried the code below. It seems that the selected parameter is being passed to checkbox and I can see the data being populated on the console. I just can't render the checkbox on form. The error I get is: typeError: this.items[0] is undefined.
testArray = new Array();
var testStore = new Ext.data.JsonStore({
proxy:new Ext.data.HttpProxy({
method:'GET',
prettyUrls:false,
url:'kiu.htm',
listeners:{
'loadexception':{
fn:test.form.data.loadException
}
}
}),
fields:["id", "display"],
reader:new Ext.data.JsonReader({
id:'id',
root:'results',
totalProperty:'totalCount',
fields:new Ext.data.Record.create([
{name:'id',type:'int'},
{name:'display',type:'string'}
])
}),
listeners:{
load: function(t, records, options, success) {
for(var i=0; i<records.length; i++) {
testArray.push({name:records[i].data.id, boxLabel: records[i].data.display});
alert(testArray[i].id);
}
}
}
});
{
xtype:'combo',
id:'comboid3',
store:combostore,
displayField:'display',
valueField:'id',
tabIndex:1,
loadingText:'Loading combo...',
listeners :{
select:function(event){
testStore.baseParams = {
"comboid":Ext.getCmp('comboid3').getValue()
};
testStore.load();
}
}
},
{
xtype:'checkboxgroup',
fieldLabel:'Check',
items:testArray
}
Help will be appreciated!
Specifying the Ext JS version is always going to be helpful. It appears this must be 2.x or 3.x and not the current version.
The issue is timing, load calls are asynchronous so by attempting to utilize testArray in this fashion you are likely referencing an empty array by the time it parses the items property of your checkboxgroup. You have a couple options around this... one is to grab a reference to the checkbox group and add the items into it, the other is to not put the checkbox group in the form at all until the call returns and then add it with the populated items array. In either case it is likely that you will need to look up a component reference to either the FormPanel or the CheckboxGroup from within the load handler function and call the 'add' method to add child items.

Resources