PDA

View Full Version : Mon problem



mdavis6890
27 Feb 2011, 12:30 PM
Code that's causing me trouble




Ext.define('IDB.selectbox.SelectBox', {
extend : 'Ext.form.ComboBox',
alias : 'widget.IDB.selectbox.SelectBox',
//clearFilterOnReset:false,
triggerAction: 'all',
lastQuery: '',
linkToCombo : undefined,
linkFilter : function() {
if(this.linkToCombo) {
var linkedCombo = this.ownerCt.getComponent(this.linkToCombo.comboID);
console.log(this.linkToCombo);
console.log(this.linkToCombo.filterField+linkedCombo.getValue());
this.getStore().filter([{
property : this.linkToCombo.filterField,
value : linkedCombo.getValue(),
exactMatch : true
}]);
}
},
initComponent : function() {
this.callParent(arguments);
if(this.linkToCombo) {
var linkedCombo = Ext.ComponentQuery.query('#'+this.linkToCombo.comboID);
this.addManagedListener(linkedCombo, 'select', function() { //This is the problem line
this.clearValue();
this.fireEvent('select');
}, this);
this.on('expand', this.linkFilter, this);
}
}
});




Error:
item.on is not a function, ext-debug-all.js (line 5613):



// Within the Ext.util.Observable section:
5604 else {
5605 managedListeners.push({
5606 item: item,
5607 ename: ename,
5608 fn: fn,
5609 scope: scope,
5610 options: options
5611 });
5612
5613 item.on(ename, fn, scope, options);// Here's where the app breaks.
5614 }

Animal
27 Feb 2011, 3:37 PM
ComponentQuery returns an array of matching Components...

Try using down on an encapsulating Container.

mdavis6890
28 Feb 2011, 3:53 PM
Yeah, that did it. I changed the line to:



var linkedCombo = Ext.ComponentQuery.query('#'+this.linkToCombo.comboID)[0];


Now it works just fine. I'm taking it for granted that the ID I pass will be unique (only return a single item).

Maybe you can help me figure out a better way to do what I want: Build in an automatic linkage for comboboxes.

Here's the full code:




Ext.define('IDB.selectbox.SelectBox', {
extend : 'Ext.form.ComboBox',
alias : 'widget.IDB.selectbox.SelectBox',
//clearFilterOnReset:false,
triggerAction: 'all',
lastQuery: '',
linkToCombo : undefined,
linkFilter : function() {
if(this.linkToCombo) {
var linkedCombo = this.ownerCt.getComponent(this.linkToCombo.comboID);
console.log(this.linkToCombo);
console.log(this.linkToCombo.filterField+linkedCombo.getValue());
this.getStore().filter([{
property : this.linkToCombo.filterField,
value : linkedCombo.getValue(),
exactMatch : true
}]);
}
},
initComponent : function() {
this.callParent(arguments);
if(this.linkToCombo) {
var linkedCombo = Ext.ComponentQuery.query('#'+this.linkToCombo.comboID)[0];
console.log(linkedCombo);
console.log(this);
this.addManagedListener(linkedCombo, 'select', function() {
this.clearValue();
this.fireEvent('select');
}, this);
/*
*/
this.on('expand', this.linkFilter, this);
}
}
});



Usage :





items : [{
fieldLabel: 'Datacenter',
xtype : 'IDB.selectbox.Site',
name : 'site_code',
itemId : 'siteCombo',
listeners : {
click : function() {
console.log(this);
}
}
},{
fieldLabel: 'Cage',
xtype : 'IDB.selectbox.Cage',
name : 'cage',
itemId : 'cageCombo',
linkToCombo : {
comboID : 'siteCombo',
filterField : 'site_code'
}
},{
fieldLabel: 'Row',
xtype : 'IDB.selectbox.Row',
name : 'row',
itemId : 'rowCombo',
linkToCombo : {
comboID : 'cageCombo',
filterField : 'cage_id'
}
},{
fieldLabel: 'Rack',
xtype : 'IDB.selectbox.Rack',
name : 'rack',
itemId : 'rackCombo',
linkToCombo : {
comboID : 'rowCombo',
filterField : 'row_id'
}
}]




I can't directly pass a reference to the combo, since they aren't created yet when I define the items, so that doesn't work. I'm instead passing a string, which I use later to find the reference to the combo (my erroneous line from above). Got any better ideas?

Thanks,
Michael

Animal
1 Mar 2011, 8:54 AM
CQ is definitely the way to go.

What I would do is ask the owning FormPanel to find the sibling ComboBox.

And I'd implement linked combos using a plugin.

mdavis6890
27 Mar 2011, 11:49 AM
Animal,

I've been distracted getting my code upgraded to Ext 4, but finally got back to this thing. I took your advice and implemented it as a plugin. I'd like to get some feedback from you on it, including any improvements or alternate approaches you might suggest.

- I used the store.filter() method, but would it be better to do something with the combo's beforequery event? I tried briefly and failed.

- There seems to be a problem where the first click 'stutters' and the combo closes up again. The second click works fine and shows the filtered list.

- I don't know what you mean by 'CQ' (oh crap, I think I just figured it out while typing. Did you mean combo query?! Dang, I knew that would have been better, but I couldn't get it working).

First, the plugin itself:




Ext.define('IDB.selectbox.LinkedComboPlugin', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.linkedcombo',
/*
Must pass object like
{
comboId : 'myLinkedCombo',
thisField : 'thisField',
thatField : 'thatField'
}
*/
linkedCombo : undefined,
init : function(combo) {
combo.on('afterrender', this.onComboRender, this);
},
onComboRender : function(combo) {
var lc = Ext.ComponentQuery.query('#'+this.linkedCombo.comboId)[0];
//Watch to see when the linked combo changes, then clear this combo's value and fire the 'select' event
//so that a series of these will all clear themselves.
combo.mon(lc, 'select', function() {
combo.clearValue();
combo.fireEvent('select');
}, this);
//I think I could filter the options somehow with the beforequery event, but a minor attempt failed.
combo.on('beforequery', function(e) {
}, this);
//When this combo is expanded, stop and filter the store first based on the linked combo's selected record.
combo.on('expand', function(picker) {
var record = lc.idbGetRecord();
if(record) {
var thatValue = record.get(this.linkedCombo.thatField);
combo.store.clearFilter();
combo.store.filter([{
property : this.linkedCombo.thisField,
value : thatValue,
exactMatch : true
}]);
}
}, this);
}
});



Intended Usage:




items : [{
fieldLabel: 'Datacenter',
xtype : 'IDB.selectbox.Site',
name : 'site_code',
itemId : 'siteCombo'
},{
fieldLabel: 'Cage',
xtype : 'IDB.selectbox.Cage',
name : 'cage',
itemId : 'cageCombo',
plugins : [
{
ptype: 'linkedcombo',
linkedCombo : {
comboId : 'siteCombo',
thisField : 'site_code',
thatField : 'site_code'
}
}
]
},{
fieldLabel: 'Row',
xtype : 'IDB.selectbox.Row',
name : 'row',
itemId : 'rowCombo',
plugins : [
{
ptype: 'linkedcombo',
linkedCombo : {
comboId : 'cageCombo',
thisField : 'cage_id',
thatField : 'id'
}
}
]
},{
fieldLabel: 'Rack',
xtype : 'IDB.selectbox.Rack',
name : 'rack',
itemId : 'rackCombo',
plugins : [
{
ptype: 'linkedcombo',
linkedCombo : {
comboId : 'rowCombo',
thisField : 'row_id',
thatField : 'id'
}
}
]
}]



Ext.form.ComboBox extention:




Ext.define('IDB.selectbox.SelectBox', {
extend : 'Ext.form.ComboBox',
alias : 'widget.IDB.selectbox.SelectBox',
idbGetRecord : function() {
return this.store.findRecord(this.valueField, this.getValue(), 0, false, true, true);
},
initComponent : function() {
Ext.apply(this, {
triggerAction: 'all',
lastQuery: ''
});
this.callParent(arguments);
}
});




I can imagine other people wanting to use this, so anything I can do to further generalize it would be good too.

I also think my idbGetRecord function on the ComboBox ought to be added to the main line.