PDA

View Full Version : Master slave combos using extjs



ahsan.shafiq
24 Oct 2007, 5:51 AM
Hi,
First of all, i am new to extjs, so please forgive if i exhibit some dumbness.:)
I want to have 3 ext js combos. The first combo is populated from a local (js file) store. I want to populate the second combo from a url, based on the value selected in the first combo. Something like "mypage.php?selectedValue=myvalue ". And then i want to populate the third combo based on the selected value from the second combo, via a url, similar to above .
Only thing i know is that may be i should be using httpproxy and json data store but how ? i have no idea of that.
Yes, i have tried the documentation but couldn't find any example for this behavior. (please correct me if i am wrong)
I would be obliged if any can guide me through step by step instructions on how to achieve this functionality. It would be gr8 , if some could show sample code achieving this functionality .
I am really stuck and i would really appreciate if any one here can help me.
Kind Regards,
Ahsan

dhanek
24 Oct 2007, 6:50 AM
U can try this..

combobox1.on('select', function () {
datastore2.proxy = new Ext.data.HttpProxy({url:'testURL&myValue='+
combobox1.getValue(), method:'get'});
datastore2.reload();
});

Good Luck!!!!

tryanDLS
24 Oct 2007, 7:41 AM
Did you look at this tutorial? http://extjs.com/learn/Tutorial:Linked_Combos_Tutorial_for_Ext_2

Also, if you're just starting with Ext, I suggest you go immediately to the 2.0beta version. There's no point in learning 1.x and then have to migrate.

ahsan.shafiq
24 Oct 2007, 8:44 PM
dhanek: Thanx for replying, i will surely try that and share the results .
tryanDLS: Yep, i had seen that , but, the application that i have been assigned to work on is built using extjs 1.1 so for now, can't switch to 2.0 8-|

ahsan.shafiq
24 Oct 2007, 9:10 PM
dhanek: I have tried that but the code u gave doesn't seem to work (most probably i am not using that code in the proper way).
Can you (or any one else) please post the complete code of a simple 2 combo scenario, where on select of first combo , the 2nd combo is being populated from a url .
I would be obliged.
Kind Regards,
Ahsan

ahsan.shafiq
24 Oct 2007, 9:41 PM
ok, here is my code (may be this would help identify the problem):



// i have picked this store from the example
var store = new Ext.data.SimpleStore({
fields: ['abbr', 'state'],
data : Ext.jsondata.states // from states.js
});



var statesCombo = new Ext.form.ComboBox({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: store,
displayField:'state',
mode: 'local',
emptyText:'Select a state...',
selectOnFocus:true,
resizable:false
});
statesCombo.applyTo('stateCombo');






var RecordDef = Ext.data.Record.create([
{name: 'value'}, // "mapping" property not needed if it's the same as "name"
{name: 'text'} // This field will use "occupation" as the mapping.
]);
var myReader = new Ext.data.XmlReader({
record: "countyRow", // The repeated element which contains row information
root:"counties"

}, RecordDef);


var ds = new Ext.data.Store({

proxy: new Ext.data.HttpProxy({
url: '../serveAjax.php'
}),

reader: myReader

});



var countiesCombo = new Ext.form.ComboBox({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: ds,
displayField:'state',
mode: 'local',
emptyText:'Select a County...',
selectOnFocus:true,
resizable:false
});
countiesCombo.applyTo('myCounties');



so, i want the counties to be populated dynamically on selection of a particular state.
Thanking in anticipation.
Kind Regards,
Ahsan

ahsan.shafiq
24 Oct 2007, 11:06 PM
ok... i have successfully made the httpProxy request...


var store = new Ext.data.SimpleStore({
fields: ['abbr', 'state'],
data : Ext.jsondata.states // from states.js
});


var statesCombo = new Ext.form.ComboBox({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: store,
displayField:'state',
mode: 'local',
emptyText:'Select a state...',
selectOnFocus:true,
resizable:false
});
statesCombo.applyTo('<%=ddlState.ClientID %>');
statesCombo.on("select",populateCounties);






var RecordDef = Ext.data.Record.create([
{name: 'value'}, // "mapping" property not needed if it's the same as "name"
{name: 'text'} // This field will use "occupation" as the mapping.
]);
var myReader = new Ext.data.XmlReader({
record: "countyRow", // The repeated element which contains row information
root:"counties"

}, RecordDef);


var ds = new Ext.data.Store({

proxy: new Ext.data.HttpProxy({
url: '../serveAjax.aspx'
}),
reader: myReader,
baseParams:{state:Ext.get('<%=ddlState.ClientID %>').getValue()}

});



var countiesCombo = new Ext.form.ComboBox({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: ds,
displayField : 'text',
valueField : 'value',
mode: 'remote',
emptyText:'Select a County...',
selectOnFocus:true,
resizable:false
});
countiesCombo.applyTo('<%=ddlCounty.ClientID %>');




Now , what i want to achieve is :

call populateCounties() on select of state combo and refresh the counties based on states selection
To attach currently state into the url i.e. 'serveAjax.aspx/


My Questions :
how do i attach the selected state value to the url ? am i using baseParam the right way?
how to reload the counties store (in populateCounties()) to get latest values from the aspx page based on selected state?

How to do these basic modifications in this code ?
Kind Regards,
Ahsan

ahsan.shafiq
25 Oct 2007, 12:57 AM
ok, now i am facing another problem. When ever i click on 2nd combo(), it calls its store.load() some how... where as i don't want it to update its values / options. What i wanted to acheive is to select a state from first combo and populate the 2nd combo,i.e counties based on the selection of state. This works fine now. But, after the dstore_of_2nd_combo.reload() successfully populates the 2nd combo with new values, 2nd combo again updates it self by calling the same url with no param, so eventually nothing happens.
I am just wondering the problem might be with 'triggerAction' ?
Any clues?

kubens
25 Oct 2007, 1:06 AM
You must use params attribute of the load method



ds.load({params: params})

ahsan.shafiq
25 Oct 2007, 3:23 AM
but i never call ds.load method....:-?
below is the code that i am using, can you point out at what point should i call the ds.load method?



function initForm()
{
if(document.getElementById('<%=ddlState.ClientID %>') != null) {
var store = new Ext.data.SimpleStore({
fields: ['abbr', 'state'],
data : Ext.jsondata.states // from states.js
});






var statesCombo = new Ext.form.ComboBox({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: store,
displayField:'state',
mode: 'local',
emptyText:'Select a state...',
selectOnFocus:true,
resizable:false
});
statesCombo.applyTo('<%=ddlState.ClientID %>');
statesCombo.on("select",function(){

// alert(1);
ds.reload({params:{state:Ext.get('<%=ddlState.ClientID %>').getValue()}})
// alert(typeof ds);
//alert(ds.options)





});
}


if(document.getElementById('<%=ddlCounty.ClientID %>') != null) {


var RecordDef = Ext.data.Record.create([
{name: 'value'}, // "mapping" property not needed if it's the same as "name"
{name: 'text'} // This field will use "occupation" as the mapping.
]);
var myReader = new Ext.data.XmlReader({
record: "countyRow", // The repeated element which contains row information
root:"counties"

}, RecordDef);


var ds = new Ext.data.Store({

proxy: new Ext.data.HttpProxy({
url: '../serveAjax.aspx'
},),
reader: myReader
//, baseParams:{state:Ext.get('<%=ddlState.ClientID %>').getValue()}

});



var countiesCombo = new Ext.form.ComboBox({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: ds,
displayField : 'text',
valueField : 'value',
mode: 'remote',
emptyText:'Select a County...',
selectOnFocus:true,
resizable:false
});
countiesCombo.applyTo('<%=ddlCounty.ClientID %>');
}
}
Ext.onReady(initForm);


Please help me soon in this as i am way too frustrated with my dumbness:D

kubens
25 Oct 2007, 4:03 AM
Sorry for confusing you. Load or reload including params option are both good. I looked at your source and I made some little modifications. I am not able to test this, but I am sure that it will work.



var App = function(){
return {

dsState: null,
cbState: null,
recCounty: null,
readerCounty: null,
dsCounty: null,
cbCounty: null,

init: function()
{
if(document.getElementById('<%=ddlState.ClientID %>') != null) {
this.dsState = new Ext.data.SimpleStore
({
fields: ['abbr', 'state'],
data : Ext.jsondata.states // from states.js
});

this.cbState = new Ext.form.ComboBox
({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: this.dsState,
displayField:'state',
mode: 'local',
emptyText:'Select a state...',
selectOnFocus:true,
resizable:false
});
this.cbState.applyTo('<%=ddlState.ClientID %>');
this.cbState.on
(
'select',
function()
{
App.dsCounty.reload( {params: this.getValue()} )
},
this
);
};

if(document.getElementById('<%=ddlCounty.ClientID %>') != null) {
this.recCounty = Ext.data.Record.create
([
{name: 'value'}, // "mapping" property not needed if it's the same as "name"
{name: 'text'} // This field will use "occupation" as the mapping.
]);
this.readerCounty = new Ext.data.XmlReader
(
{
record: "countyRow", // The repeated element which contains row information
root: "counties"
},
this.recCounty
);

this.dsCounty = new Ext.data.Store
({
proxy: new Ext.data.HttpProxy
({
url: '../serveAjax.aspx',
method: 'GET'
}),
reader: this.readerCounty
});

this.cbCounty = new Ext.form.ComboBox
({
cls: 'comboFieldNoMargin',
fieldClass: 'comboFieldNoMargin',
selectedClass: 'comboFieldSelected',
shadow: false,
editable: false,
typeAhead: true,
triggerAction: 'all',
width: 200,
forceSelection:true,
store: this.dsCounty,
displayField : 'text',
valueField : 'value',
mode: 'remote',
emptyText:'Select a County...',
selectOnFocus:true,
resizable:false
});
this.cbCounty.applyTo('<%=ddlCounty.ClientID %>');
}
}

}();
Ext.onReady(App.init, App);


At least I hope that this will work :">

Br
Wolfgang

pongz79
25 Oct 2007, 6:08 AM
I was having the same problem but with this tip

Load or reload including params option are both good
I solved it.

Now i have a question.
When i reload my 2nd ComboBox with filtered data how can i get the totalProperty number of records returned by the server?
Because i want to test it, if is 0 i want to reset the 2nd ComboBox.
Here is an example:

{"total":0,"sample":null}

Best reguards:
Tiago Oliveira

kubens
25 Oct 2007, 6:20 AM
this.dsCounty = new Ext.data.Store
({
proxy: new Ext.data.HttpProxy
({
url: '../serveAjax.aspx',
method: 'GET'
}),
reader: this.readerCounty,
listeners:
{
'load': function ()
{
if (this.getTotalCount() == 0)
{
alert('No Counties available')
}
}
}
});

pongz79
25 Oct 2007, 6:44 AM
@kubens:
Seems like i can't adapt that to my example.
I'll paste here my code to see if anyone can point me the right direction.


var chooseBuildingsWindow;
var myButton = Ext.get("buildingsButton");

myButton.on('click', function(){
if (!chooseBuildingsWindow) {
chooseBuildingsWindow = new Ext.Window({
layout: 'fit',
animateTarget: "buildingsButton",
draggable: true,
width: 350,
height: 300,
closeAction: 'close',
plain: true,
buttons: [{
text: 'Submit'
},{
text: 'Close',
handler: function(){
chooseBuildingsWindow.hide();
}
}],
items: [
new Ext.form.FormPanel({
id: 'buildingsFloorsForm',
method: 'POST',
labelAlign: 'right',
title: 'Choose Building / Floor',
bodyStyle: 'padding: 5px 5px 0',
width: 300,
defaults: {xtype: 'combo'},
items: [{
shadow: false,
editable: false,
forceSelection: true,
id: 'combo-buildings',
store: new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: 'buildings.php',
method: 'POST'
}),
reader: new Ext.data.JsonReader({
totalProperty: 'total',
root: 'sample',
id: 'bid'
}, [
{name: 'bid'},
{name: 'name'}
])
}),
displayField: 'name',
valueField: 'bid',
typeAhead: true,
mode: 'remote',
triggerAction: 'all',
emptyText: 'Choose Building...',
fieldLabel: 'Select Building',
selectOnFocus: true,
resizable: false,
listeners: {select:{fn:function(combo, value) {
var comboFloors = Ext.getCmp('combo-floors');
comboFloors.enable();
comboFloors.reset();
comboFloors.store.reload({params:{selectedValue: combo.getValue()} });
}}}
}, {
store: new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: 'floors.php',
method: 'POST'
}),
reader: new Ext.data.JsonReader({
totalProperty: 'total',
root: 'sample',
id: 'id'
} , [
{name: 'id'},
{name: 'bid'},
{name: 'name'}
])
}),
listeners: {
'reload': function() {
var comboFloors = Ext.getCmp('combo-floors');
if (comboFloors.getTotalCount() == 0) {
alert("No floors available");
}
}
},
displayField: 'name',
valueField: 'id',
typeAhead: true,
mode: 'local',
triggerAction: 'all',
emptyText: 'Choose Floor...',
selectOnFocus: true,
fieldLabel: 'Select Floor',
disabled: true,
id: 'combo-floors'
}]
})
]
})
}
chooseBuildingsWindow.show(this);
});

Best reguards:
Tiago Oliveira

kubens
25 Oct 2007, 6:50 AM
if (comboFloors.store.getTotalCount() == 0)

pongz79
25 Oct 2007, 7:01 AM
@kubens:
That doesn't work.
In my database i have:
Table buildings:


bid name
1 Building 1
2 Building 2
3 Building 3
4 Building 4

Table floors:


id bid name
1 1 R/C
2 1 Floor 1
3 1 Floor 2
4 1 Floor 3
5 2 R/C
6 2 Floor 1
7 2 Floor 2
8 3 R/C

My 2nd ComboBox is properly populated when i choose "Building 1", "Building 2" or "Building 3", but when i choose "Building 4" the 2nd ComboBox stays with the values that were previously selecetd instead of empty.
What i'm i doing wrong?

Best reguards:
Tiago Oliveira

kubens
25 Oct 2007, 7:10 AM
Are you sure that store will reloaded properly?
Instead of comboFloors.reset() try to use comboFloors.removeAll()

pongz79
25 Oct 2007, 7:25 AM
@kubens:



Are you sure that store will reloaded properly?


Here is my returned data from the server:
Building 1:


{"total":4,"sample":[{"id":"1","bid":"1","name":"R\/C"},{"id":"2","bid":"1","name":"Floor 1"},{"id":"3"

,"bid":"1","name":"Floor 2"},{"id":"4","bid":"1","name":"Floor 3"}]}

Building 2:


{"total":3,"sample":[{"id":"5","bid":"2","name":"R\/C"},{"id":"6","bid":"2","name":"Floor 1"},{"id":"7"

,"bid":"2","name":"Floor 2"}]}

Building 3:


{"total":1,"sample":[{"id":"8","bid":"3","name":"R\/C"}]}

Building 4:


{"total":0,"sample":null}




Instead of comboFloors.reset() try to use comboFloors.removeAll()


comboFloors.removeAll() is not a function of Ext.form.ComboBox

Damn...I'm getting desperate :((
Sorry for the observation... :">

Best reguards:
Tiago Oliveira

kubens
25 Oct 2007, 7:30 AM
comboFloors.store.removeAll()

kubens
25 Oct 2007, 7:31 AM
{"total":0,"sample":[]}

pongz79
25 Oct 2007, 7:34 AM
Damn kubens, that did the trick :D
Thank you very much.
I'll hold you one ;)

Best reguards:
Tiago Oliveira