PDA

View Full Version : Weird MultiSelect ComboBox beforedeselect behavior.



incutonez
29 May 2014, 10:12 AM
I have a ComboBox that has multiSelect as true. This ComboBox has an initial value set, which is selected when I open the ComboBox. The problem becomes when I want to use ComboBox.setValue... using this function apparently fires off the beforedeselect event, but not the select event. And the odd thing is, beforedeselect is only fired for the values that I'm setting in setValue.

Please see this example (https://fiddle.sencha.com/#fiddle/673).

To reproduce the issue, you can do the following:

Click the "Set ComboBox Value" button
Click the drop down
You should then see 4 alerts: Maryland, Pennsylvania, Maryland, Pennsylvania

or


Click the drop down
You should then see 2 alerts: Colorado, Colorado
Click the "Set ComboBox Value" button
You should see 1 alert: Colorado
Click the "Set ComboBox Value" button again
You should see 2 alerts: Maryland, Pennsylvania

Maybe I'm misunderstanding the event, but why is this the behavior? Why would using setValue deselect the states (that I'm setting) from the ComboBox, but still have them selected when I open the ComboBox? And why does the first test case show 4 alerts?

Update

Looking at the syncSelection (http://docs.sencha.com/extjs/4.2.1/source/ComboBox.html#Ext-form-field-ComboBox-method-syncSelection) code, it looks like deselectAll is called on the selection model, which would explain why the beforedeselect event is called, but the selection model then calls select... which doesn't explain why the selection event is not called.



Ext.onReady(function() {
var store = Ext.create('Ext.data.Store', {
fields: ['state_id', 'state_name'],
data: [
{state_id: 1, state_name: 'Colorado'},
{state_id: 2, state_name: 'Maryland'},
{state_id: 3, state_name: 'Pennsylvania'}
]
});
var combo = Ext.create('Ext.form.field.ComboBox', {
valueField: 'state_id',
displayField: 'state_name',
store: store,
multiSelect: true,
value: [1],
listeners: {
beforedeselect: function(combo, record, index, eOpts) {
alert('deselected: ' + record.get('state_name'));
},
beforeselect: function() {
alert('selected');
}
},
renderTo: Ext.getBody()
});
var button = Ext.create('Ext.button.Button', {
text: 'Set ComboBox Value',
listeners: {
click: function() {
combo.setValue([2, 3]);
}
},
renderTo: Ext.getBody()
});
});

incutonez
29 May 2014, 12:29 PM
I've come up with a solution, but I'm unsure of the repercussions... so far, I haven't seen any. I override the comboBox's syncSelection method with the following:



syncSelection: function() {
var me = this,
picker = me.picker,
selection, selModel,
values = me.valueModels || [],
vLen = values.length, v, value;

if (picker) {
// From the value, find the Models that are in the store's current data
selection = [];
for (v = 0; v < vLen; v++) {
value = values[v];

if (value && value.isModel && me.store.indexOf(value) >= 0) {
selection.push(value);
}
}

// Update the selection to match
me.ignoreSelection++;
selModel = picker.getSelectionModel();
selModel.deselectAll(true); // This is the key to it all... suppressing the event listener, just like what's happening in the select right below this
if (selection.length) {
selModel.select(selection, undefined, true);
}
me.ignoreSelection--;
}
}


The only change is the deselectAll call... it's now suppressing the deselect event that's fired... I'm curious to know why they don't suppress the event like they do in the select. Like I said, I'm not sure of the repercussions, but it's given me great mileage thus far.