简体   繁体   中英

ExtJS : Re-selecting the same value does not fire the select event

Normally, when you select an item in a combobox, you would expect it to fire the select event. However, if you try to select an item that was already selected, the select event is not fired. That is the "normal" behavior of an ExtJs combobox.

I have a specific need for an ExtJS combobox: I need it to fire the select event even if I re-select the same value. But I cannot get it to work. Any help would be much appreciated!

Example here: https://fiddle.sencha.com/#view/editor&fiddle/2n11 Open the dev tools to see when the select event is fired.

I'm using ExtJS Classic 6.6.0.

Edit: I answered my own question and updated the Fiddle with working solution.

try to look at this: ExtJS 4 Combobox event for selecting selected value

Its for earlier ExtJS version, but catching click event for itemlist may help you out too..

I found the culprit: it all happens in the SelectionModel of the combobox BoundList, in the method doSingleSelect.

So if we extend Ext.Selection.DataViewModel and Ext.form.field.ComboBox, we can force the select event to be fired every time.

Ext.define( "MyApp.selection.DataViewModelExt", {
    "extend": "Ext.selection.DataViewModel",
    "alias": "selection.dataviewmodelext",

    "doSingleSelect": function(record, suppressEvent) {
        var me = this,
            changed = false,
            selected = me.selected,
            commit;

        if (me.locked) {
            return;
        }
        // already selected. 
        // should we also check beforeselect? 
        /*
        if (me.isSelected(record)) {
            return;
        }
        */

        commit = function() {
            // Deselect previous selection. 
            if (selected.getCount()) {
                me.suspendChanges();
                var result = me.deselectDuringSelect([record], suppressEvent);
                if (me.destroyed) {
                    return;
                }
                me.resumeChanges();
                if (result[0]) {
                    // Means deselection failed, so abort 
                    return false;
                }
            }

            me.lastSelected = record;
            if (!selected.getCount()) {
                me.selectionStart = record;
            }
            selected.add(record);
            changed = true;
        };

        me.onSelectChange(record, true, suppressEvent, commit);

        if (changed && !me.destroyed) {
            me.maybeFireSelectionChange(!suppressEvent);
        }
    }
});

We also must extend the combobox to force using our extended DataViewModel. The only thing to change is the onBindStore method where it instancies the DataViewModel:

Ext.define( "MyApp.form.field.ComboBoxEx", {
    "extend": "Ext.form.field.ComboBox",
    "alias": "widget.comboboxex",

    "onBindStore": function(store, initial) {
        var me = this,
            picker = me.picker,
            extraKeySpec,
            valueCollectionConfig;

        // We're being bound, not unbound... 
        if (store) {
            // If store was created from a 2 dimensional array with generated field names 'field1' and 'field2' 
            if (store.autoCreated) {
                me.queryMode = 'local';
                me.valueField = me.displayField = 'field1';
                if (!store.expanded) {
                    me.displayField = 'field2';
                }

                // displayTpl config will need regenerating with the autogenerated displayField name 'field1' 
                if (me.getDisplayTpl().auto) {
                    me.setDisplayTpl(null);
                }
            }
            if (!Ext.isDefined(me.valueField)) {
                me.valueField = me.displayField;
            }

            // Add a byValue index to the store so that we can efficiently look up records by the value field 
            // when setValue passes string value(s). 
            // The two indices (Ext.util.CollectionKeys) are configured unique: false, so that if duplicate keys 
            // are found, they are all returned by the get call. 
            // This is so that findByText and findByValue are able to return the *FIRST* matching value. By default, 
            // if unique is true, CollectionKey keeps the *last* matching value. 
            extraKeySpec = {
                byValue: {
                    rootProperty: 'data',
                    unique: false
                }
            };
            extraKeySpec.byValue.property = me.valueField;
            store.setExtraKeys(extraKeySpec);

            if (me.displayField === me.valueField) {
                store.byText = store.byValue;
            } else {
                extraKeySpec.byText = {
                    rootProperty: 'data',
                    unique: false
                };
                extraKeySpec.byText.property = me.displayField;
                store.setExtraKeys(extraKeySpec);
            }

            // We hold a collection of the values which have been selected, keyed by this field's valueField. 
            // This collection also functions as the selected items collection for the BoundList's selection model 
            valueCollectionConfig = {
                rootProperty: 'data',
                extraKeys: {
                    byInternalId: {
                        property: 'internalId'
                    },
                    byValue: {
                        property: me.valueField,
                        rootProperty: 'data'
                    }
                },
                // Whenever this collection is changed by anyone, whether by this field adding to it, 
                // or the BoundList operating, we must refresh our value. 
                listeners: {
                    beginupdate: me.onValueCollectionBeginUpdate,
                    endupdate: me.onValueCollectionEndUpdate,
                    scope: me
                }
            };

            // This becomes our collection of selected records for the Field. 
            me.valueCollection = new Ext.util.Collection(valueCollectionConfig);

            // This is the selection model we configure into the dropdown BoundList. 
            // We use the selected Collection as our value collection and the basis 
            // for rendering the tag list.
            //me.pickerSelectionModel = new Ext.selection.DataViewModel({
            me.pickerSelectionModel = new MyApp.selection.DataViewModelExt({
                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE',
                // There are situations when a row is selected on mousedown but then the mouse is dragged to another row 
                // and released.  In these situations, the event target for the click event won't be the row where the mouse 
                // was released but the boundview.  The view will then determine that it should fire a container click, and 
                // the DataViewModel will then deselect all prior selections. Setting `deselectOnContainerClick` here will 
                // prevent the model from deselecting. 
                ordered: true,
                deselectOnContainerClick: false,
                enableInitialSelection: false,
                pruneRemoved: false,
                selected: me.valueCollection,
                store: store,
                listeners: {
                    scope: me,
                    lastselectedchanged: me.updateBindSelection
                }
            });

            if (!initial) {
                me.resetToDefault();
            }

            if (picker) {
                me.pickerSelectionModel.on({
                    scope: me,
                    beforeselect: me.onBeforeSelect,
                    beforedeselect: me.onBeforeDeselect
                });

                picker.setSelectionModel(me.pickerSelectionModel);

                if (picker.getStore() !== store) {
                    picker.bindStore(store);
                }
            }
        }
    }
});

Then just use the extended combobox in your app. By doing that, the select event will be fired every time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM