I write special combo object to use it as linked combos. Here it is:
comboDivClass = Ext.extend(Ext.form.ComboBox, {
fieldLabel: 'Divisions',
anchor: '95%',
lazyRender:true,
store:new Ext.data.Store({
proxy: proxy,
baseParams:{rfb_type:'divisions'},
reader: divReader,
autoLoad: true
}),
displayField:'div_name',
allowBlank:false,
valueField:'div_id',
triggerAction:'all',
mode:'local',
listeners:{
select:{
fn:function(combo, value) {
if (this.idChildCombo) {
var modelCmp = Ext.getCmp(this.idChildCombo);
modelCmp.setValue('');
modelCmp.getStore().reload({
params: { 'div_id': this.getValue() }
});
}
}
}
},/**/
hiddenName:'div_id',
initComponent: function() {comboDivClass.superclass.initComponent.call(this);}})
As you may see, this combobox load data at child combobox store(which set as idChildCombo).
Ok. Here is how i declare it
new comboDivClass({id:'sub0div',idChildCombo:'sub1div'}),
new comboDivClass({id:'sub1div'})
Yes it works, but it have some odd trouble - it load not only sub1div store, it load at sub0div store too. Why? What im doing wrong?
One thing I see is that you have mode: 'local' config, while it should be remote.
Other thing to consider: Why don't you do it more like this:
var c1 = new comboDivClass({id:'sub0div'});
var c2 = new comboDivClass({id:'sub1div'});
c1.on('select',function(combo, value) {c2.getStore().reload({
params: { 'div_id': c1.getValue() }
})});
ChildCombo.setMasterField( masterField ) {
masterField.on('change', function(field){
this.getStore().filterBy( function(){ //filter by masterFIeld.getValue() } );
})
}
The idea is to link child field to parent not parent to child and this way you can link to any kind form field no only combo.
Here in child combo you have to have store with three columns [group,value,label] where group is value of master field.
This way you can manage to have mode than one master field.
Related
I want to create checkbox group from store populated from an array.
Here is my store.
var checklistStore = new Ext.data.Store({
data: arraySubT,
fields: ['id', 'boxLabel']
});
and currently my checkbox group in only getting displayed from an array and not store.
xtype: 'checkboxgroup',
fieldLabel: 'Checklist',
columns: 1,
vertical: true,
listeners: {
change: function(field, newValue, oldValue, eOpts){
}
},
items: checkboxconfigs
However I want to make it displayed from store.How can I achieve this?
[EDIT]
For your and my convenience, I made a general component which you can use. It may need some tuning regarding the store events that it reacts to. Find it in this fiddle.
[/EDIT]
You have to do it manually:
renderCheckboxes:function() {
checkboxgroup.removeAll();
checkboxgroup.add(
checklistStore.getRange().map(function(storeItem) {
return {
// map the storeItem to a valid checkbox config
}
})
);
}
and repeat that over and over and over again when the store data changes. That is, you have to attach to the store events:
checklistStore.on({
load:renderCheckboxes,
update:renderCheckboxes,
datachanged:renderCheckboxes,
filterchange:renderCheckboxes,
...
})
Maybe you will overlook some events you have to attach to, but sooner or later you will have all edge cases covered.
Here is working fiddle for you.
Just loop through store data with Ext.data.Store.each() method and setup your checkbox group items.
var _checboxGroupUpdated = function() {
// Use whatever selector you want
var myCheckboxGroup = Ext.ComponentQuery.query('panel checkboxgroup')[0];
myCheckboxGroup.removeAll();
myStore.each(function(record) {
myCheckboxGroup.add({
boxLabel: record.get('fieldLabel'),
inputValue: record.get('value'),
name: 'myGroup'
});
});
}
// Add all listeners you need here
myStore.on({
load: _checboxGroupUpdated,
update: _checboxGroupUpdated,
datachanged: _checboxGroupUpdated
// etc
});
I'm trying to get a return value of my json store to setValue in my combobox. The value of this json value is the current selected option in the database. My this.selectedCat store returns the current category value of the record where it's working in. my this.store returns all the available select options.
var fields = {
fields: ['text']
};
var notfields ={
fields:['category']
}
this.store = new GO.data.JsonStore({
url: GO.settings.modules.infoscherm.url + 'json.php',
baseParams:{
task:'selects'
},
root: 'results',
fields: fields.fields
});
this.selectedCat = new GO.data.JsonStore({
url: GO.settings.modules.infoscherm.url + 'json.php',
baseParams: {
task:'currentselectedcat',
id:'id'
},
root: 'results',
fields: notfields.fields
});
this.category = new Ext.form.ComboBox({
name: 'category',
width: 100,
store: this.store,
fieldLabel: "Categorie",
displayField:'text',
triggerAction: 'all',
editable: false,
selectOnFocus:true,
value: this.selectedCat //returns [object Object] naturally
});
Am I doing something wrong?
I think you need to start listening the "load" event of "Ext.data.JsonStore".
And the attached handler of "load" event will contain code to select any particular value by using "setValue" function of combobox object...
P.S. : Store values are made available in combobox drop down menu only if you configured the "store" config of combobox to the store object, in your case, you need to implement some logic within the handler of "load" event.
I have a combo box inside a form like:
xtype: 'combo',
id: 'example',
name: 'ax',
triggerAction: 'all',
forceSelection: true,
editable: false,
allowBlank: false,
fieldLabel: 'example',
mode: 'remote',
displayField:'name',
valueField: 'id',
store: Ext.create('Ext.data.Store', {
fields: [
{name: 'id'},
{name: 'name'}
],
//autoLoad: false,
proxy: {
type: 'ajax',
url: 'example.php',
reader: {
type: 'json',
root: 'rows'
}
}
}
})
I don't want that auto load because that's slow when i start.
But i want set a value to combo box when i click edit button and load value to combo
this.down('form').getForm().load({
url: 'load.php',
success:function(){
}
});
data from load.php like (name of combe is ax)
{ success:true , data : { ax: '{"id":"0","name":"defaults"}' } }
But that's not working. How can i do that thanks.
p/s: If i have autoLoad : true and data is { success:true , data : { ax: '0' } } that's work well. But that's slow when i start.
What you want to do is make sure the combo is loaded before you try to set it's value.
You could check if the combo's store has any data in it:
if(combo.getStore().getCount() > 0)
{
//the store has data so it must be loaded, you can set the combo's value
//doing a form.load will have the desired effect
}
else
{
//the store isn't loaded yet! You can't set the combo's value
//form.load will not set the value of the combo
}
If it does, you can just set the value. But more likely however it will not have been loaded.
You could also do something like this
//in the controller's init block
this.control({
"#myEditButton" : {click: this.loadForm}
});
//a function in your controller
loadForm: function(button)
{
var combo; //get your combo somehow, either via references or via the button
combo.getStore().load({
scope: this,
callback:
function(records, operation, success)
{
if(success)
{
//load your form here
}
}
});
}
I know that might seem like a lot of code, but it's the only way to know for sure if the combo was loaded. If it is not, you cannot set it's value.
A third option would just be to explicitly load the store before you open your view.
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;
I am using EXTJS with an editorgridpanel and I am trying to to insert a combobox, populated with JsonStore.
Here is a snapshot of my code:
THE STORE:
kmxgz.ordercmpappro.prototype.getCmpapproStore = function(my_url) {
var myStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: my_url
, method: 'POST'
})
, reader: new Ext.data.JsonReader({
root: 'rows',
totalProperty: 'total',
id: 'list_cmpappro_id',
fields: [
{name: 'list_cmpappro_id', mapping: 'list_cmpappro_id'}
, {name: 'list_cmpappro_name', mapping: 'list_cmpappro_name'}
]
})
, autoLoad: true
, id: 'cmpapproStore'
, listeners: {
load: function(store, records, options){
//store is loaded, now you can work with it's records, etc.
console.info('store load, arguments:', arguments);
console.info('Store count = ', store.getCount());
}
}
});
return myStore;
};
THE COMBO:
kmxgz.ordercmpappro.prototype.getCmpapproCombo = function(my_store) {
var myCombo = new Ext.form.ComboBox({
typeAhead: true,
lazyRender:false,
forceSelection: true,
allowBlank: true,
editable: true,
selectOnFocus: true,
id: 'cmpapproCombo',
triggerAction: 'all',
fieldLabel: 'CMP Appro',
valueField: 'list_cmpappro_id',
displayField: 'list_cmpappro_name',
hiddenName: 'cmpappro_id',
valueNotFoundText: 'Value not found.',
mode: 'local',
store: my_store,
emptyText: 'Select a CMP Appro',
loadingText: 'Veuillez patienter ...',
listeners: {
// 'change' will be fired when the value has changed and the user exits the ComboBox via tab, click, etc.
// The 'newValue' and 'oldValue' params will be from the field specified in the 'valueField' config above.
change: function(combo, newValue, oldValue){
console.log("Old Value: " + oldValue);
console.log("New Value: " + newValue);
},
// 'select' will be fired as soon as an item in the ComboBox is selected with mouse, keyboard.
select: function(combo, record, index){
console.log(record.data.name);
console.log(index);
}
}
});
return myCombo;
};
The combobox is inserted in an editorgridpanel.
There's a renderer like this:
Ext.util.Format.comboRenderer = function(combo){
return function(value, metadata, record){
alert(combo.store.getCount()); //<== always 0!!
var record = combo.findRecord(combo.valueField || combo.displayField, value);
return record ? record.get(combo.displayField) : combo.valueNotFoundText;
}
};
When the grid is displayed the first time, instead of have the displayField, I have : "Value not found."
And I have the alert : 0 (alert(combo.store.getCount())) from the renderer.
But I can see in the console that the data have been correctly loaded!
Even if I try to reload the store from the renderer (combo.store.load();), I still have the alert (0)!
But when I select the combo to change the value, I can see the data and when I change the value, I can see the displayFiel!
I don't understand what's the problem?
Since now several days, I already tried all the solutions I found...but still nothing!
Any advice is welcome!
Yoong
The core of the problem is that you need to hook an listener which will execute after the grid store loaded. That listener will then convert the combo grid content to the displayField content instead of valueField.
Here is my resolution to this issue.
Ext.ns("Ext.ux.renderer");
Ext.ux.renderer.ComboBoxRenderer = function(combo, grid) {
var getValue = function(value) {
var record = combo.findRecord(combo.valueField, value);
return record ? record.get(combo.displayField) : value;
};
return function(value) {
var s = combo.store;
if (s.getCount() == 0 && grid) {
s.on({
load: {
single: true,
fn: function() {
grid.getView().refresh()
}
}
});
return value
}
return getValue(value)
}
};
You can use this renderer in your code like the following:
{
header: 'Header',
dataIndex: 'HeaderName',
autoWidth: true,
renderer: Ext.ux.renderer.ComboBoxRenderer(combo, grid),
editor: combo
}
This is a common issue. If you need a store value to display in the combo, handle the store's load event and select the appropriate value in the combo only after that. You shouldn't need a specific record just to render the combo up front.
I would recommend adding the field required from the combobox's store, to the grid's store, and change the renderer to use that field. (It does not have to be in the database)
and on the afteredit event of the grid, grab that value from the combobox's store and copy it to the grid's store.
This would yield better performance.
Actually, the problem seems to be that the grid renders the combobox values BEFORE the loading of the store data.
I found something here.
But when I applied the override, still the same problem...
The question i: how to defer the render of the combobox, waiting for the loading of the store?