extjsextjs6-modernextjs7

Modern 7.0 ComboBox fires 'select' event on every value change


The combobox in modern fires the "select" event every time the input changes. This is very different from classic. With it doing this there is no way to differentiate between a user making a selection and pragmatically setting the value of the field.

This was reported as a bug in the Sencha forums:

https://www.sencha.com/forum/showthread.php?468730-Modern-6-5-2-ComboBox-fires-select-event-on-every-value-change

The link above also contains a fiddler to demonstrate the issue.

Has anyone run into this as an issue, and how did you overcome it?


Solution

  • forceSelection: true will help to solve this problem but will not cancel the bug in cases when forced selection is not needed

    Edit:

    This behavior is due to method syncValue (search in this source - method is private and hasn't documentation)

    I don’t understand why the component developer chose to create a record even if it isn’t exist.

    Comment from source file:

    Either user has typed something (isInput), or we've had a setValue to a value which has no match in the store, and we are not forceSelection: true. We create a new record.

    I propose to fix this behavior using the following override:

    fiddle

    Ext.define('Ext.field.SelectOverride', {
        override: 'Ext.field.Select',
        autoCreateRecord: false,
        syncValue: function() {
            var me = this,
                store = me.getStore(),
                forceSelection = me.getForceSelection(),
                valueNotFoundText = me.getValueNotFoundText(),
                is, isCleared, isInput, value, matchedRecord;
    
    
            if (me.reconcilingValue || !store || !store.isLoaded() || store.hasPendingLoad()) {
                return;
            }
    
            me.reconcilingValue = true;
    
            me.getSelection(); // make sure selection config is flushed
    
            is = {};
            is[me.syncMode] = true;
            value = ((isInput = is.input || is.filter)) ? me.getInputValue() : me.getValue();
            isCleared = value == null || value === '';
    
    
            if (!isCleared) {
                if (me.getMultiSelect()) {
                    return me.syncMultiValues(Ext.Array.from(value));
                }
    
                matchedRecord = (isInput ? store.byText : store.byValue).get(value);
    
                if (matchedRecord) {
                    if (!matchedRecord.isEntity) {
    
                        matchedRecord = matchedRecord[0];
                    }
                }
                else if (!forceSelection) {
                    matchedRecord = me.findRecordByValue(value);
                }
            }
    
            // Either user has typed something (isInput), or we've had a setValue
            // to a value which has no match in the store, and we are not forceSelection: true.
            // We create a new record.
            if (!isCleared && !matchedRecord && !forceSelection && me.autoCreateRecord) {
                matchedRecord = me.createEnteredRecord(value);
            }
            else {
                if (isInput || is.store) {
                    if (!matchedRecord && forceSelection) {
                        me.setValue(null);
                        me.setSelection(null);
    
                        if (!is.filter) {
                            me.setFieldDisplay();
                        }
                    }
                }            else {
                    if (isCleared) {
                        if (me.mustAutoSelect()) {
                            matchedRecord = store.first();
    
                            if (me.getAutoSelect() === 'initial') {
                                me.setAutoSelect(false);
                            }
                        }
                        else {
                            me.setSelection(null);
                        }
                    }
                    else if (!matchedRecord && valueNotFoundText) {
                        me.setError(valueNotFoundText);
                    }
                }
            }
    
            if (matchedRecord) {
                me.setSelection(matchedRecord);
            }
    
            me.reconcilingValue = false;
        }
    });