UPDATE -
I HAVE ALSO MADE A MOCK IN JSFIDDLE http://jsfiddle.net/mAgfU/371/
AND WITH A FORM PANEL : http://jsfiddle.net/kA6mD/2/
I have the bellow comboox.
When I use the following code to set the form values:
this.form.loadRecord(data);
the entire form is acting ok except from the combo.
instead of giving me the displayField, I get the valueField in the display.
As you can see in the image above, the combo should show the word "Walla" (displayField) instead of "1" (valueField)
Ext.define('App.view.ForeignCombo', {
extend: 'Ext.form.ComboBox',
alias: 'widget.foreigncombo',
queryMode: 'local',
displayField: 'Name',
valueField: 'Id',
editable: false,
matchFieldWidth: false,
constructor: function(config) {
Ext.apply(this, config);
Ext.define('BrnadComboModel', {
extend: 'Ext.data.Model',
fields: ['Id', 'Name']
});
this.store = Ext.create('Ext.data.Store', {
model: 'BrnadComboModel',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/api/Brand/',
reader: {
type: 'json',
root: 'Results'
}
},
pageSize: 50,
});
this.callParent();
}
}
);
this is how I use it:
{
"xtype": 'foreigncombo'
, "name": 'Brand.Id'
, "fieldLabel": 'Brand.Id'
}
There is no race bewtween the form display and the combo ajax request, the combo store is autoLoad:true, meaning I see that it has already been loaded...
Thanks
I used your fiddle a an example. Place a breakpoint in line 87 (Ext.ComponentQuery.query('comobobox')....), in this fiddle http://jsfiddle.net/kA6mD/9/, and set a watch to Ext.ComponentQuery.query('combobox')[0].store.data.. you'll notice the store has no data. This may be linked to what I mentioned in the comment.
I know there must be a better way of doing this, but what I usually use as a workaround is either load the store at some point before in the app or use a synchronous Ext.Ajax.request and load each record at a time in the store.
As this is a combo for brands I suppose you could load the store before (i.e. app load) and lookup for the store instead of creating a new one each time you create a foreigncombo component, so the first solution should work.
As for the second workaround it should also work, it takes a little bit more coding but its actually pretty easy. It should look something like this...
Ext.Ajax.request({
url:'your/url/',
async:false,
.....
success:function(response){
var records = Ext.JSON.decode(response.responseText);
for(var m=0; m<records.length; m++){
var record = Ext.create('YourBrandModel',{
abbr:records[m].abbr,
name:records[m].name
});
store.add(record);
}
}
})
You should do this as few times as possible as it may slow down the user experience if it gets called everytime you create a "foreigncombo", so checking if this store exists before creating one might be a good idea.
Please take in cosideration that I have not tested this code, so you may have to tweak it a little in order for it to work. But it should get you on tracks.
Related
I am trying to use Ext's (4.1.1) buffered store/grid combination with data, which I cannot access directly through a rest Api.. or so, but the incoming data is handled by my controller and want just add this data to the buffered grid.
And here comes the problem, when I load 500 items directly to the store, the buffering is working.. Only items which I can see gets rendered, but when I start to store.add(items) then they all gets automatically rendered..
So this is my store & grid:
Store
this.store = Ext.create('Ext.data.ArrayStore', {
storeId: 'reportDataStore',
fields: [
{ name: 'html'}
],
buffered: true,
pageSize: 100,
autoLoad: true
});
Grid
{
xtype: 'gridpanel',
flex: 1,
hideHeaders: true,
store: this.store,
verticalScroller: {
rowHeight: 43
},
disableSelection: true,
columns: [
{ header: '', dataIndex: 'html', flex: 1 }
]
}
Data Controller
...
// somewhere in initialization process of the controller,
// I take the reportDataStore, for later reusing
this.reportDataStore = Ext.getStore('reportDataStore');
...
onNewData: function(data) {
this.reportDataStore.add(data)
}
So my expectation was, that data will get into the store, but only the visible data will get rendered.. Now it is so, that all new data gets rendered.
I wasn't able to produce a working example with the code you give, but I've got something close... How did you even manage to add records to a buffered store backed by a memory proxy?
You should try to push your new data to the proxy directly, and then reload the store, like so:
store.proxy.data.push(data);
grid.view.saveScrollState();
// should probably have been a call to reload(), but then the loading never ends...
store.load({
callback: function() {
grid.view.restoreScrollState();
}
});
See this fiddle that tries to reproduce your setup.
I'm using instances of a combobox for multiple user interfaces. So I need to reset combobox stores when user focuses on it. Combo's store is locally sorted; so I execute clearFilter() function of Ext.data.Store class - it works as it is expected except that typing query does not work anymore.
Here is my combobox configuration:
forceSelection: true,
autoSelect: false,
typeAhead: false,
triggerAction: 'all'
Store configuration:
autoLoad: false,
autoSync: false,
remoteSort: false,
proxy: {
type: 'ajax'
// other configs
}
Edit: fiddle
Note: Store of combobox used in fiddle is populated with static data when the original one uses an AJAX proxy
I think i solved your problem by looking at this post:
ExtJs: Search / Filter within a ComboBox
Adding a custom filter on each keystroke on the combobox seems to resolve your issue:
enableKeyEvents:true,
listeners: {
'keyup': function() {
this.getStore().clearFilter();
this.getStore().filter('name', this.getRawValue(), true, false);
},
'beforequery': function(queryEvent) {
queryEvent.combo.onLoad();
}
}
It is not beautiful, but i think it works. Take a look at this extended fiddle:
https://fiddle.sencha.com/#fiddle/teg
As I understand from your fiddle, you have trouble that implementing filter to different comboboxes. I think the problem you currently use same store for comboboxes. That's why you should also change the store for each combobox. Add this code to your fiddle.
combo1.getStore().filter('nationality', 'USA');
container.on('tabchange', function(tabpanel, newCard, oldCard, eOpts) {
combo2.getStore().clearFilter();
combo1.getStore().filter('nationality', 'USA');
if (combo2.getValue()) {
combo1.getStore().clearFilter();
combo1.getStore().filter('userId', combo2.getValue())
}
});
Btw, I put the filter before tabchange event because of static store. But, you might want to add the filter store listener if you use proxy(AJAX) store. Like this:
listeners: {
load: function(store, records) {
store.filter('nationality', 'USA');
}
}
Edit:
var store = combo1.getStore();
store.filter('nationality', 'USA');
container.on('tabchange', function(tabpanel, newCard, oldCard, eOpts) {
if (newCard.title == 'Panel 1') {
store.clearFilter();
store.filter('nationality', 'USA');
} else if (newCard.title == 'Panel 2') {
store.clearFilter();
// Or whatever filter because you have to change the store
// dynamically if you wanna use same store for different combos
}
});
Hope this helps. Good luck.
I want to use a very simple combo box in ExtJS, but I was surprised to learn that it seems as though I have to complexify things by using a store.
I have a single array of data :
var states = [
{"name":"Alabama"},
{"name":"Alaska"}
]
I create my model 'State' linking to the 'name' field, and then I create my store linking to the model, and the array of data.
Ext.regModel('State', {
fields: [
{type: 'string', name: 'name'}
]
});
var store1 = Ext.create('Ext.data.Store', {
model: 'State',
data: states
});
Now I create my combo, as a field in my panel :
var f = Ext.create('Ext.form.Panel', {
items: [
{
fieldLabel: 'hi there',
xtype: 'combobox',
name: 'XXXX',
store:store1,
maxLength: 64,
allowBlank: false
}
]
})
Nothing tells me that I am doing anything wrong, but I get an 'Uncaught TypeError: Cannot read property 'indexOf' of undefined ' whenever I try and open the combo.
My fiddle is here :
http://jsfiddle.net/sr61tpmd/1/
Another aside to my question is, what is the simplest way I can present a combobox in ExtjS?
As long as you only want a combo box with same value as displayed, it is entirely possible to define the store as an array.
xtype:'combo',
store:['Alabama','Arkansas',...]
A real extjs store is necessary where your displayed text differs from the value. You can see a working example for this (also using the us states, actually) in the ext docs: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.form.field.ComboBox
I have a little problem. At my application Im always building two linked combobox - country and towns(then country are selected - towns began to load). So i thinked - mbe write a constructor and minimized my code? Ok i did it. But i got a problem: i have 2-3 couple of this linked comboboxes on page and when i selected at second combo country, the data (towns) loads at first combo, because it has the same id. Ok - now im trying take a param id to constructor and it didnt work. How set id of combobox then i create an object?
Country combo
comboCountryClass = Ext.extend(Ext.form.ComboBox, {
fieldLabel: 'country',
anchor: '95%',
lazyRender:true,
store:new Ext.data.Store({
proxy: new Ext.data.HttpProxy(
{url: '../lib/getRFB.php?rfb_type=countrys',
method: 'GET'}
),
reader: countryReader,
autoLoad: true
}),
displayField:'country_name',
valueField:'country_id',
triggerAction:'all',
mode:'local',
listeners:{
select:{
fn:function(combo, value) {
var modelCmp = Ext.getCmp(this.town_name_id);
alert(this.town_name_id);
modelCmp.setValue('');
modelCmp.getStore().proxy.setUrl('../lib/getRFB.php');
modelCmp.store.reload({
params: { 'country_id': this.getValue(),rfb_type: 'towns' }
});
}
}
},
hiddenName:'country_id',
initComponent: function() {comboCountryClass.superclass.initComponent.call(this);}})
And town combo
comboTownClass = Ext.extend(Ext.form.ComboBox, {
fieldLabel:'town',
displayField:'town_name',
valueField:'town_id',
hiddenName:'town_id',
anchor: '95%',
id:this.town_name_id || 'youuuu',
store: new Ext.data.Store({
proxy: new Ext.data.HttpProxy(
{url: 'lib/handlers/orgHandler.php?action=read&towns=true',
method: 'GET'}
),
reader: townReader
}),
triggerAction:'all',
mode:'local',
initComponent: function() {comboTownClass.superclass.initComponent.call(this);}})
new comboTownClass({town_name_id:'townFormSearch'})
new comboCountryClass({town_name_id:'townFormSearch'})
You can set the id of the component by doing the following:
new comboTownClass({id:'townComboId'});
new comboCountryClass({id:'countryComboId'});
You can specify a default id, and when you pass an id in the config param it will overwrite the default value.
Although I agree with #Upper Stage you should try to limit the amount of hard-coded id values you have in the form - you can instead grab form elements using the form name instead.
I live by the rule: "never use hardcoded IDs." You can retrieve a unique ID from Ext JS using
Ext.id( null, 'someTextString' )
You will incur more bookkeeping when you use unique IDs, but you will not run into the problem about which you write above.
Sometimes I store unique IDs locally in an object and then reference that instance variable where necessary.
this.idForCombo = Ext.id( null, 'someTextString' );
var myCmp = new SomeConstructor({
id: this.idForCombo,
...more stuff });
myCombobox.id = yourId;
when trying to populate A ENTIRE GRID using the ajax from a combobox in the select listener when i try to recall or reload the datastore i'm still getting the old values, instead of the new ones. i have to get the new values because according to the parameter selected in the combobox the textfields and the others editor will populate with that json data read from server using ajax, accoding with another combobox that fetch remote data
var cm = new Ext.grid.ColumnModel({
defaults: {
sortable: true
},
columns: [{
id: 'ci',
header: 'Periodo Declarado',
dataIndex: 'ci',
width: 150,
editor: new fm.ComboBox({
typeAhead: true,
triggerAction: 'all',
transform: 'PerDecl',
lazyRender: true,
listClass: 'x-combo-list-small',
mode:'local',
listeners:{
expand: function (combo){
//alert("asd");
},
collapse: function(combo,record,number){
},
select:function(v, params, record){
ds_random_employee_data_active.remove();
var varAnio2=v.getValue();
var ds_random_employee_data_active2=ds_random_employee_data_active;
ds_random_employee_data_active2.load({ params: { anio: varAnio2 } });
Ext.each(ds_random_employee_data_active2.data.items, function(record){
alert(record.data.ut);
});
//setTimeout("tres("+ v +"[]);",1000);
}}
})
}
***********others columns************************
[SOLVED] THANKS U ALL for say i figure it out after four hours or more the way i did is seemed to bmoeskau but i did read the post of bmoeskau after i've got with the solution
thanks u to all
store.load({params:{anio:varanio},callback:function(){// here comes the loop or another instruction
}})
this is a nice forum chat
That's because it loads asynchronously.
If you (re)load a data store, the call is asynchronous, so any action that relies on the updated data must be done within a callback. You can handle the store's load event to do that. See my answer here for an example.