Hybrid View

    Success! Looks like we've fixed this one. According to our records the fix was applied for EXTJS-8947 in 4.2.1.744.
  1. #1
    Sencha Premium Member
    Join Date
    Feb 2012
    Location
    Raleigh, NC
    Posts
    423
    Vote Rating
    153
    brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold

      0  

    Default 4.2 ComboBox Query Enhancements

    4.2 ComboBox Query Enhancements


    First, please add config options to combobox for anyMatch and caseSensitive, which are passed to the stored queryFilter.

    Second, please add code to the top of doQuery for:

    Code:
    if( queryString.length < this.minChars ) {
            forceAll = true;
    }
    Because when using field validation (allowBlank: false, forceSelection: true, typeAhead: true), and deleting values typed into the combo box, the full list does not appear (basically forceAll isn't being forced to true).

    Thanks,

    Brian

  2. #2
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,507
    Vote Rating
    56
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    Good ideas. The 4.2.0 release is frozen, but I'll add a ticket.

  3. #3
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,507
    Vote Rating
    56
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    I think what you need to provide the expected user experience is below. Let me know if that works for you.

    Code:
    Ext.override(Ext.form.field.ComboBox, {
        doQuery: function(queryString, forceAll, rawQuery) {
            queryString = queryString || '';
    
            // store in object and pass by reference in 'beforequery'
            // so that client code can modify values.
            var me = this,
                qe = {
                    query: queryString,
                    forceAll: forceAll,
                    combo: me,
                    cancel: false
                },
                store = me.store,
                isLocalMode = me.queryMode === 'local';
    
            if (me.fireEvent('beforequery', qe) === false || qe.cancel) {
                return false;
            }
    
            // get back out possibly modified values
            queryString = qe.query;
            forceAll = qe.forceAll;
    
            // Re-filter if forceAll being passed
            //  or query string is at least the required length
            //  or dropdown is visible and the user will expect feedback - eg erasing and widening the query.
            if (forceAll || (queryString.length >= me.minChars) || (me.picker && me.picker.isVisible())) {
                // expand before starting query so LoadMask can position itself correctly
                me.expand();
    
                // make sure they aren't querying the same thing
                if (!me.queryCaching || me.lastQuery !== queryString) {
                    me.lastQuery = queryString;
    
                    if (isLocalMode) {
    
                        // Querying by a typed string...
                        if (queryString || !forceAll) {
    
                            // Ensure queryFilter is enabled and set the new value
                            me.queryFilter.disabled = false;
                            me.queryFilter.setValue(me.enableRegEx ? new RegExp(queryString) : queryString);
                        }
    
                        // Disable query value filter if no query string or forceAll passed
                        else {
                            me.queryFilter.disabled = true;
                        }
    
                        // Filter the Store according to the updated filter
                        store.filter();
                    } else {
                        // Set flag for onLoad handling to know how the Store was loaded
                        me.rawQuery = rawQuery;
    
                        // In queryMode: 'remote', we assume Store filters are added by the developer as remote filters,
                        // and these are automatically passed as params with every load call, so we do *not* call clearFilter.
                        if (me.pageSize) {
                            // if we're paging, we've changed the query so start at page 1.
                            me.loadPage(1);
                        } else {
                            store.load({
                                params: me.getParams(queryString)
                            });
                        }
                    }
                }
    
                // Clear current selection if it does not match the current value in the field
                if (me.getRawValue() !== me.getDisplayValue()) {
                    me.ignoreSelection++;
                    me.picker.getSelectionModel().deselectAll();
                    me.ignoreSelection--;
                }
    
                if (isLocalMode) {
                    me.doAutoSelect();
                }
                if (me.typeAhead) {
                    me.doTypeAhead();
                }
            }
            return true;
        }
    });

  4. #4
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,604
    Vote Rating
    325
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      0  

    Default


    My understanding of minChars is that it's to be used with very large, remote datasets where a short query is too small to meaningfully filter the results set. It kind of defeats the purpose if the user can just delete their way around it.

    Could a beforequery listener not be used to achieve the desired effect without any modifications to combobox itself?

  5. #5
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,507
    Vote Rating
    56
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    That's true.

    But for local datasets, it's intuitive that the query widens as you erase.

    Perhaps the fix should be

    Code:
    if (forceAll || (queryString.length >= me.minChars) || (isLocalMode && me.picker && me.picker.isVisible())) {

  6. #6
    Sencha Premium Member
    Join Date
    Feb 2012
    Location
    Raleigh, NC
    Posts
    423
    Vote Rating
    153
    brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold brian428 is a splendid one to behold

      0  

    Default


    Quote Originally Posted by Animal View Post
    That's true.

    But for local datasets, it's intuitive that the query widens as you erase.

    Perhaps the fix should be

    Code:
    if (forceAll || (queryString.length >= me.minChars) || (isLocalMode && me.picker && me.picker.isVisible())) {
    Sounds right as a more general solution. For me, I've got a custom AnyMatchComboBox that I use only for local data sets. So for simplicity, I just have this (I'm using CoffeeScript):

    Code:
    config:
      anyMatch: true
      caseSensitive: false
    
    initComponent: ->
      @callParent( [ arguments ] )
      @queryFilter.anyMatch = @anyMatch
      @queryFilter.caseSensitive = @caseSensitive
      
    doQuery: ( queryString="", forceAll, rawQuery ) ->
      forceAll = true if queryString.length < @minChars
      @callParent( queryString, forceAll, rawQuery )
      return true