1
votes

Requesting a sanity check here please...

ExtJS 4.2 comboBox Typeahead works but having issues retrieving the valueField under the following conditions:-

1) If a user types a value and then instead of hitting enter or clicking on the select combo list, they click elsewhere then the valueField is empty but the selected value is present.

2) Assuming that the combobox item was selected correctly, If I enter an additional character and then backspace that character, the combo box can no longer find the valueField..its almost like it has reset itself.

Fiddle example

https://fiddle.sencha.com/#fiddle/je1

How to reproduce

If you enter Maggie in the combo box, you will see the valueField ID in the console window, if you append a character and then backspace the character, the ID in the console window is null

(You will need to open the console window to see the output)

forceSelection does not resolve this issue as I have a template and it will not accept an entry in the combobox that is not part of the store, and I need to use sumID for my valueField as I need to retrieve and pass that value to the server.

2
It looks like the behaviour is consistent. I do not get an id even when typing "Maggie" until I select "Maggie" and the same is true if I then add/delete any characters to the search string and then select "Maggie" again.Rob Schmuecker
Hi Rob, you are correct..I just replayed my behavior..it seems that the typeAhead works but does not "set" until I either hit enter...let me update the case to reflect that..user3524762
Can you amend your fiddle to use an xTemplate as you do in your application?Rob Schmuecker
I cannot update fidlder example as the tpl is using some css classes to create a button that the user selects, the button is to "select all names" and list that in the combo box which foreSelection would ignore if selected.user3524762
When you select Maggie and then type and backspace a character, you have not really 'completed' the process of selection. (Notice how the dropdown is still visible?) Practically, to complete the selection process, you will either click somewhere else (maybe a submit button), or press ENTER/ESCAPE and once you do that, you do get the value you expect.Amol Katdare

2 Answers

1
votes

Thank you everyone, awesome to have such a great community!!

I was able to get around this by using forceSelection and overriding the setValue thus allowing template items not in the store but in the combo to be selected via forceSelection. From playing around with the combobox, IMO, for a good look and feel, forceSelection is the way to go.

Here is my override, refer to statement //start of override

This was a quick fix, I will refine statement when I am back in the office, below I am pasting the solution from memory, you get the idea.

setValue: function(value, doSelect) {
        var me = this,
            valueNotFoundText = me.valueNotFoundText,
            inputEl = me.inputEl,
            i, len, record,
            dataObj,
            matchedRecords = [],
            displayTplData = [],
            processedValue = [];

        if (me.store.loading) {
            // Called while the Store is loading. Ensure it is processed by the onLoad method.
            me.value = value;
            me.setHiddenValue(me.value);
            return me;
        }

        // This method processes multi-values, so ensure value is an array.
        value = Ext.Array.from(value);

        // Loop through values, matching each from the Store, and collecting matched records
        for (i = 0, len = value.length; i < len; i++) {
            record = value[i];
            if (!record || !record.isModel) {
                record = me.findRecordByValue(record);
            }
            // record found, select it.
            if (record) {
                matchedRecords.push(record);
                displayTplData.push(record.data);
                processedValue.push(record.get(me.valueField));
            }
            // record was not found, this could happen because
            // store is not loaded or they set a value not in the store
            else {
            //start of override

            // 'Select All Names' is the template item that was added                                     // to the combo box,  it looks like an entry from the store         
            // but it is not in the store
            if (me.forceSelection && me.getDisplayValue() === 'Select All Names'){
                    processedValue.push(value[i]);
                    dataObj = {};
                    dataObj[me.displayField] = value[i];
                    displayTplData.push(dataObj);
                }
                //end of override

                if (!me.forceSelection) {
                    processedValue.push(value[i]);
                    dataObj = {};
                    dataObj[me.displayField] = value[i];
                    displayTplData.push(dataObj);
                    // TODO: Add config to create new records on selection of a value that has no match in the Store
                }
                // Else, if valueNotFoundText is defined, display it, otherwise display nothing for this value
                else if (Ext.isDefined(valueNotFoundText)) {
                    displayTplData.push(valueNotFoundText);
                }
            }
        }

    // Set the value of this field. If we are multiselecting, then that is an array.
    me.setHiddenValue(processedValue);
    me.value = me.multiSelect ? processedValue : processedValue[0];
    if (!Ext.isDefined(me.value)) {
        me.value = null;
    }
    me.displayTplData = displayTplData; //store for getDisplayValue method
    me.lastSelection = me.valueModels = matchedRecords;

    if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
        inputEl.removeCls(me.emptyCls);
    }

    // Calculate raw value from the collection of Model data
    me.setRawValue(me.getDisplayValue());
    me.checkChange();

    if (doSelect !== false) {
        me.syncSelection();
    }
    me.applyEmptyText();

    return me;
},
0
votes

Look at the sources of Combobox and try override this method as follows

doLocalQuery: function(queryPlan) {
    var me = this,
        queryString = queryPlan.query;


    if (!me.queryFilter) {

        me.queryFilter = new Ext.util.Filter({
            id: me.id + '-query-filter',
            anyMatch: me.anyMatch,
            caseSensitive: me.caseSensitive,
            root: 'data',
            property: me.displayField
        });
        me.store.addFilter(me.queryFilter, false);
    }


    if (queryString || !queryPlan.forceAll) {
        me.queryFilter.disabled = false;
        me.queryFilter.setValue(me.enableRegEx ? new RegExp(queryString) : queryString);
    }


    else {
        me.queryFilter.disabled = true;
    }


    me.store.filter();


    if (me.store.getCount()) {
        if (me.rawValue === me.lastSelection[0].get(me.displayField)){
            me.setValue(me.lastSelection);
        } else {
            if(me.store.getCount() === 1){
                me.setValue(me.store.first());
            }
            me.expand();
        }
    } else {
        me.collapse();
    }

    me.afterQuery(queryPlan);
},