PDA

View Full Version : ComboBox filter not bubbling up to options until second filter attempt



JKeane
16 Aug 2011, 10:24 AM
I have a popup window that holds a FormPanel with a handful of fields. One of the things I need to do is link some of the child ComboBoxes so that making a selection in one forces a filter on a subsequent one. I've set up a change event so that the Store of the subsequent combo is filtered (like the ComboBox's doQuery method, but filtering on valueField instead of displayField). However, the filtering only flows to the options after I make a choice, even though I have certified that Store is indeed filtered.

See code below, and the comments next to the two alerts.


Ext.define("CF.view.Edit", {
extend: "Ext.window.Window",
alias: "widget.edit",
title: "Client Fees - Edit",
width: 320,
height: 260,
autoShow: true,
buttonAlign: "left",
initComponent: function () {
this.items = [{
xtype: "form",
frame: true,
fieldDefaults: {
labelWidth: 120
},
items: [{
xtype: "textfield",
name: "companyname",
fieldLabel: "Company/Sponsor"
}, {
xtype: "combo",
name: "productseq",
id: "productseq",
fieldLabel: "Product",
store: new CF.store.Products(),
queryMode: "local",
displayField: "productName",
valueField: "productSeq"
}, {
xtype: "combo",
disabled: false,
name: "feetype",
id: "feetype",
fieldLabel: "Fee Type",
store: new CF.store.FeeTypes(),
queryMode: "local",
displayField: "financeFeeDesc",
valueField: "financeFeeSeq",
forceSelection: true
}, {
xtype: "hiddenfield",
name: "iconproductcode",
id: "iconproductcode"
}, {
xtype: "textfield",
disabled: true,
name: "iconproductname",
id: "iconproductname",
fieldLabel: "ICON Product"
}, {
xtype: "numberfield",
name: "feeamt",
fieldLabel: "Fee ($)",
hideTrigger: true,
keyNavEnabled: false,
mouseWheelEnabled: false
}, {
xtype: "combo",
name: "feemonth",
fieldLabel: "Month",
queryMode: "local",
forceSelection: true,
store: (function () {
var x = [],
i;
for (i = 0; i < 12; i++) {
x.push([i + 1, Ext.Date.monthNames[i]]);
}
return x;
})()
}, {
xtype: "combo",
name: "feeyear",
fieldLabel: "Year",
queryMode: "local",
forceSelection: true,
store: (function () {
var x = [],
year;
for (year = 2007; year <= (new Date).getFullYear(); year++) x.unshift(year);
return x;
})()
}]
}];

// this.down("#productseq").on("change", function(field,value) {
// //Ext.getCmp("iconproductcode").setValue(null);
// //Ext.getCmp("iconproductname").setValue(null);
// Ext.getCmp("feetype").store.filter(productSeq, value);
// });
// this.down("#feetype").on("change", function(field,value) {
// var icon = field.store.get("");
// Ext.getCmp("iconproductcode").setValue(null).store.filter("iconProductCode",value);
// });
this.on("afterrender", function (w) {
w.down("#productseq").on("change", function (field, value) {
//Ext.getCmp("iconproductcode").setValue(null);
//Ext.getCmp("iconproductname").setValue(null);
alert(Ext.getCmp("feetype").store.getCount()) //displays 160 in my test case
Ext.getCmp("feetype").store.clearFilter(true);
Ext.getCmp("feetype").store.filter("productSeq", value);
alert(Ext.getCmp("feetype").store.getCount()) //now it displays 2 as it should, but this is not reflected in the front-end
});
})

this.buttons = [{
text: 'Save',
action: 'save'
}, {
text: 'Cancel',
scope: this,
handler: this.close
}];

this.callParent(arguments);
}
});

skirtle
16 Aug 2011, 4:58 PM
I suspect your filter is being cleared when you click the trigger. This can be prevented using lastQuery:

http://docs.sencha.com/ext-js/4-0/#/api/Ext.form.field.ComboBox-property-lastQuery

JKeane
17 Aug 2011, 5:59 AM
Here's the thing though: it works as it should whenever I expand the ComboBox and select an option. It's on render that the problem happens.

Ext experts, please feel free to correct me, but I believe this is what happens in the scenario originally mentioned:


CF.view.Edit is instantiated
The view's render event triggers, which assigns the change event to ComboBox named productseq.
The calling Grid's Controller (which instantiated CF.view.Edit) tells the FormPanel inside the Window to load the record
FormPanel.loadRecord sets the value of the productseq ComboBox
productseq fires off the change event


I suspect this because of the debug alerts. On instantiation, the first alert signals the full size of the Store - 160 rows, in this case. Post-filter, the second alert shows the appropriate number of rows for a given product -- usually around 2, but it varies depending on the selection. However, the ComboBox still shows all 160 rows. Then I make change to a different value for productseq. Again, the pre-filter alert displays -- the 2 or whatever rows from the previous selection. Filter is cleared and reapplied, the post-filter alert displays the new row count, and the filter now works as expected.

skirtle
17 Aug 2011, 8:06 AM
Would you be able to produce a short reproducible test case? Your current test case is quite long and full of code that clearly has no bearing on the problem. Ideally it should be some JS that we could just drop into a shell HTML page. At the moment your code has a lot of external dependencies (e.g. the stores) that make it hard for us to try it ourselves.

This isn't just about making it easier for us, it is often this trimming process that identifies the cause of a problem.

JKeane
17 Aug 2011, 11:03 AM
Certainly. I've broken it down to just be two interrelated ComboBoxes backed by very simple stores. I also created a basic object that stores values to load into the form. And it's still not filtering properly until after the data is loaded and I click to expand the dropdown. Please let me know if I need to strip it down further.


var Products, FeeTypes, TestData;
Ext.define("Product", {
extend: "Ext.data.Model",
fields: [{
name: "id",
type: "int"
}, "name"]
});
Products = Ext.create("Ext.data.Store", {
model: "Product",
data: [{
id: 1,
name: "Widget"
}, {
id: 2,
name: "Gizmo"
}]
});

Ext.define("FeeType", {
extend: "Ext.data.Model",
fields: [{
name: "id",
type: "int"
}, {
name: "productId",
type: "int"
}, "name"]
});
FeeTypes = Ext.create("Ext.data.Store", {
model: "FeeType",
data: [{
id: 1,
productId: 1,
name: "Cash"
}, {
id: 2,
productId: 1,
name: "Store Credit"
}, {
id: 3,
productId: 2,
name: "Credit Card"
}]
});

Ext.define("TestRecord", {
extend: "Ext.data.Model",
fields: ["productseq", "feetype"]
});
//should match the pair "Gizmo/Credit Card"
TestData = Ext.create("TestRecord", {
productseq: 2,
feetype: 3
});

Ext.define("CF.view.Edit", {
extend: "Ext.window.Window",
alias: "widget.edit",
title: "Client Fees - Edit",
width: 320,
height: 260,
autoShow: true,
buttonAlign: "left",
initComponent: function () {
this.items = [{
xtype: "form",
frame: true,
fieldDefaults: {
labelWidth: 120
},
items: [{
xtype: "combo",
name: "productseq",
id: "productseq",
fieldLabel: "Product",
store: Products,
queryMode: "local",
displayField: "name",
valueField: "id"
}, {
xtype: "combo",
disabled: false,
name: "feetype",
id: "feetype",
fieldLabel: "Fee Type",
store: FeeTypes,
queryMode: "local",
displayField: "name",
valueField: "id",
forceSelection: true
}]
}];

this.on("afterrender", function (w) {
w.down("#productseq").on("change", function (field, value) {
Ext.getCmp("feetype").store.clearFilter(true);
Ext.getCmp("feetype").store.filter("productId", value);
});
});

this.callParent(arguments);
}
});

Ext.onReady(function () {
var b = Ext.create("Ext.Button", {
renderTo: Ext.getBody(),
text: "Push me",
autoRender: true,
listeners: {
click: function () {
var widget = Ext.widget("edit");
widget.down("form").loadRecord(TestData);
}
}
})
});

skirtle
17 Aug 2011, 3:41 PM
I'm not sure I'm reproducing the same issue that you're having. My steps are:


Click the button - a window appears.
Click the trigger for the second combobox.
The list of options is wrong given the first combobox's value.


Is this the right problem?

If it is then it is solved (for me at least) by adding:


lastQuery: ''

to the second combobox's config. The first time you click the trigger it will clear any existing filters unless you do this. This is documented in the link I provided previously.

If this isn't the problem you're seeing could you give the exact steps to reproduce using your test case?

JKeane
18 Aug 2011, 6:37 AM
Yep, lastQuery appears to have done the trick. Thanks!