PDA

View Full Version : Filtered Store / strange behavior of ComboBox



tibi
23 Nov 2007, 7:40 PM
Hi,

I'm having trouble with a ComboBox which depends on the value of another. When the first (in my example the 'customer') is selected, the second ('project') is enabled and the list of values is 'narrowed' down to valid ones (when a customer has been selected only projects for this customer should be visible). This is done via the filter() function of the store.

The problem is that clicking the second ('projects') ComboBox triggers the store to discard the filtering. I've been unable to turn this behavior off. Is there a way to do this?

Maybe this is a bug. I don't know what exactly happens, but according to Firebug, this is the difference between the first click/selection and later clicks/selections, i.e. one of these functions trigger the underlying store to forget about the filtering:

byClassName ext-all.js (line 11)
Component ext-all.js (line 58)
ComponentMgr ext-all.js (line 57)
DomHelper ext-all.js (line 9)
DomQuery ext-all.js (line 11)
getNodes ext-all.js (line 11)
initComponent ext-all.js (line 124)
initComponent ext-all.js (line 62)
Manager ext-all.js (line 81)
MixedCollection ext-all.js (line 22)
nodup ext-all.js (line 11)
Provider ext-all.js (line 80)
register ext-all.js (line 42)
Template ext-all.js (line 10)
XTemplate ext-all.js (line 25)

Any ideas? For a test case, see the pasted HTML file below.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Ext 2.0 RC1 Test Case</title>

<link rel="stylesheet" type="text/css" href="http://extjs.com/deploy/dev/resources/css/ext-all.css"/>
<script type="text/javascript" src="http://extjs.com/deploy/dev/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://extjs.com/deploy/dev/ext-all.js"></script>

<script type="text/javascript">
Ext.onReady( function(){

customers_array = [ [1, 'A'],
[2, 'B'],
[3, 'C'] ];

projects_array = [ [1, 2, "B-1"],
[2, 2, "B-2"],
[3, 2, "B-3"],
[4, 1, "A-1"] ];

customers_store = new Ext.data.SimpleStore({
fields: ['id', 'name'],
data: customers_array,
id: 0
})

Project = Ext.data.Record.create([
{name:'id'},
{name:'customer_id'},
{name:'project'},
]);

projects_store = new Ext.data.Store({
data: projects_array,
reader: new Ext.data.ArrayReader({
id: 0
}, Project)
});

projects_combobox = new Ext.form.ComboBox({
fieldLabel: 'Project',
name: 'project',
store: projects_store,
valueField: 'id',
displayField: 'project',
disabled: true
});

customers_combobox = new Ext.form.ComboBox({
fieldLabel: 'Customer',
name: 'customer',
store: customers_store,
valueField: 'id',
displayField: 'name'
});

customers_combobox.on('select',
function(_this, record, index) {
projects_store.filter('customer_id', new RegExp('^'+record['id']+'$'));
projects_combobox.enable();
});

var create_prot_form = new Ext.FormPanel({
defaults: { forceSelection: true,
mode: 'local',
editable: false,
triggerAction: 'all'
},
items: [ customers_combobox, projects_combobox ]
});

create_prot_form.render('myform');
});
</script>

</head>
<body>

<div id="myform"></div>

</body>
</html>

TiVoShane
26 Nov 2007, 9:12 AM
It doesn't appear that the filter is being forgotten, it appears that the filter is never applied.

Taking a look at Ext.util.Observable.prototype, the event datachanged never fires because this.events['datachaged'] is not an object. However, once you click the combobox, the next time the filter is run, datachanged does fire because this.events['datachanged'] is now an object.

I still have to look further into it to see when the events['datachanged'] is assigned but I would think that it should be assigned on creation instead of assigning it once the combo has been activated.

Ext.util.Observable.prototype = {
fireEvent : function(){
if(this.eventsSuspended !== true){
var ce = this.events[arguments[0].toLowerCase()];
if(typeof ce == "object"){
return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
}
}
return true;
}

TiVoShane
26 Nov 2007, 9:19 AM
OK, looking at it further it appears that the filter is applied. I need to look at this further but my guess now is that clicking on the combobox the first time fires the triggeraction which defaults to "all" and it grabs all the records again.

Further investigation required.....

TiVoShane
26 Nov 2007, 10:56 AM
tibi, if you change the on('select' to focus the combo, then do the filter, then expand it, it'll work in Mozilla. However, it doesn't work in IE7 as of yet because the expand doesn't seem to work quite right in IE7.


projects_combobox.enable();
projects_combobox.focus();
projects_store.filter('customer_id', new RegExp('^'+record['id']+'$'));
projects_combobox.expand();

TiVoShane
27 Nov 2007, 7:31 AM
OK, so a fix for IE and Firefox is this:
projects_combobox.enable();
projects_combobox.focus();
projects_combobox.fireEvent('focus');
projects_combobox.hasFocus = true;
projects_store.filter('customer_id', new RegExp('^'+record['id']+'$'));
projects_combobox.expand();

tibi
4 Dec 2007, 11:42 AM
Hey TiVoShane, thanks for looking into my problem.
Your solution didn't work well for me, I used a different approach:
In the select event handler for the first combobox, I explicitly call doQuery with forceAll=true and only afterwards apply the filter.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Ext 2.0 RC1 Test Case</title>

<link rel="stylesheet" type="text/css" href="http://extjs.com/deploy/dev/resources/css/ext-all.css"/>
<script type="text/javascript" src="http://extjs.com/deploy/dev/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://extjs.com/deploy/dev/ext-all.js"></script>

<script type="text/javascript">
Ext.onReady( function(){

customers_array = [ [1, 'A'],
[2, 'B'],
[3, 'C'] ];

projects_array = [ [1, 2, "B-1"],
[2, 2, "B-2"],
[3, 2, "B-3"],
[4, 1, "A-1"] ];

customers_store = new Ext.data.SimpleStore({
fields: ['id', 'name'],
data: customers_array,
id: 0
})

Project = Ext.data.Record.create([
{name:'id'},
{name:'customer_id'},
{name:'project'},
]);

projects_store = new Ext.data.Store({
data: projects_array,
reader: new Ext.data.ArrayReader({
id: 0
}, Project)
});

projects_combobox = new Ext.form.ComboBox({
fieldLabel: 'Project',
name: 'project',
store: projects_store,
valueField: 'id',
displayField: 'project',
disabled: true
});

customers_combobox = new Ext.form.ComboBox({
fieldLabel: 'Customer',
name: 'customer',
store: customers_store,
valueField: 'id',
displayField: 'name'
});

customers_combobox.on('select',
function(_this, record, index) {
projects_combobox.doQuery(projects_combobox.allQuery, true);
projects_store.filter('customer_id', new RegExp('^'+record['id']+'$'));
projects_combobox.enable();
});

var create_prot_form = new Ext.FormPanel({
defaults: { forceSelection: true,
mode: 'local',
editable: false,
triggerAction: 'all'
},
items: [ customers_combobox, projects_combobox ]
});

create_prot_form.render('myform');
});
</script>

</head>
<body>

<div id="myform"></div>

</body>
</html>

hendra1
3 Mar 2008, 10:22 PM
with doQuery filtering in grid works fine, thanks for your code.
You really help my coding. Thanks:):>

Condor
3 Mar 2008, 11:30 PM
You can do that with less code:


var combobox2 = new Ext.form.ComboBox({
...
triggerAction: 'all',
lastQuery: ''
});

var combobox1 = new Ext.form.ComboBox({
...
listeners: {
select: function() {
combobox2.store.filter(...);
combobox2.enable();
}
}
});

RacingTomcat
7 Mar 2008, 7:38 AM
Hi condor,

thank you very much for this:


var combobox2 = new Ext.form.ComboBox({
...
triggerAction: 'all',
lastQuery: ''
});


It works perfectly for me, when filtering a ComboBox's store or the first time after rendering.