Обычно, когда вы выбираете элемент в поле со списком, вы ожидаете, что он запустит событие выбора. Однако, если вы попытаетесь выбрать элемент, который уже был выбран, событие выбора не запускается. Это «нормальное» поведение комбинированного списка ExtJs.

У меня есть особая потребность в комбинированном списке ExtJS: мне нужно, чтобы он запускал событие выбора, даже если я повторно выберу то же значение. Но я не могу заставить его работать. Любая помощь приветствуется!

Пример здесь: https://fiddle.sencha.com/#view/editor&fiddle/2n11 Откройте инструменты разработчика, чтобы узнать, когда запускается событие выбора.

Я использую ExtJS Classic 6.6.0.

Изменить: я ответил на свой вопрос и обновил Fiddle рабочим решением.

0
Gabriel Hautclocq 25 Окт 2018 в 16:45

2 ответа

Лучший ответ

Я нашел виновника: все это происходит в SelectionModel выпадающего списка BoundList, в методе doSingleSelect.

Поэтому, если мы расширим Ext.Selection.DataViewModel и Ext.form.field.ComboBox, мы сможем каждый раз запускать событие select.

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);
        }
    }
});

Мы также должны расширить поле со списком, чтобы принудительно использовать нашу расширенную модель DataViewModel. Единственное, что нужно изменить, это метод onBindStore, в котором он создает экземпляр 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);
                }
            }
        }
    }
});

Затем просто используйте расширенное поле со списком в своем приложении. При этом событие выбора будет запускаться каждый раз.

1
Gabriel Hautclocq 26 Окт 2018 в 07:54

Попробуйте посмотреть на это: Событие ExtJS 4 Combobox для выбора выбранного значения

Это для более ранней версии ExtJS, но перехват события click для списка элементов тоже может вам помочь ..

1
Ivan Bosmansky 25 Окт 2018 в 14:42