Extjs combobox: hide selected value from dropdown list

后端 未结 5 1412
青春惊慌失措
青春惊慌失措 2021-02-15 14:57

I\'m using ExtJS 4 and looking for a way I can hide currently selected value from combo\'s dropdown list?

So instead of this (\"Alaska\" currently selected in combobox):

相关标签:
5条回答
  • 2021-02-15 15:09

    I ended up using a modified version of @sra's solution:

    Ext.define('My.ComboBox',  {
        extend: 'Ext.form.field.ComboBox',
    
        /**
         * @cfg {Boolean} hideActive=true
         * When true, hides the currently selected value from the dropdown list
         */
        hideActive: true,
    
        /**
        * @private {Ext.data.Model[]} selectedRecords
        * A Array of selected records, used when hideActive is true
        */
    
        initComponent: function() {
            this.selectedRecords = [];
    
            this.callParent();
        },
    
    
        setValue: function(value, doSelect) {
            var store = this.store;
    
            if(this.hideActive) {
                store.suspendEvents(false);
                // write the current selected back to the store (you need to suspend autoSync if active)
                // do this BEFORE callParent so the currently selected record would be found in the store
                store.add(this.selectedRecords);
            }
    
            this.callParent(arguments);
    
            if(this.hideActive) {
                // set the selected as new recordlist
                this.selectedRecords = this.valueModels;
                // remove the selected from the store
                store.remove(this.valueModels);
                store.resumeEvents();
                store.fireEvent('refresh', store);
            }
    
            return this;
        }
    
    });
    

    The 'hiding' logic is the same, only I perform it in the setValue method to make sure that it also works when programmatically setting combo's value, including the case where the combobox is initialized with a value.

    UPD Also, looks like store.add(this.selectedRecords); has to be called before this.callParent(arguments);, otherwise combobox will act weird if we attempt to set the same value twice (it simply wouldn't find the active record in the store cause we removed it, so it'll reset to blank). I suspend store's events to prevent some quirks caused by combobox trying to synchronize with its dropdown list in the middle of my manipulations with selected record(s) and manually trigger store's 'refresh' event when I'm done so the list gets eventually updated. This may have performance impact but so far I don't know a better solution.

    0 讨论(0)
  • 2021-02-15 15:16

    So I used @sra's solution, but with a small modification, to add the content in the right place below the if(!me.hideActive):

    if(me.selectedRecords[0]) {
        me.store.insert(me.selectedRecords[0].index,me.selectedRecords);
    }
    

    That way you just don't add them to the botton. I know it is an old post, but I hope it helps people looking for a solution.

    0 讨论(0)
  • 2021-02-15 15:25

    I came up with another solution that looks even simpler and a quick testing reveals no side effects:

    We can leave Combobox logic untouched but simply hide the selected item via CSS:

    .x-boundlist-selected {
        display: none;
    }
    

    And voila, we don't see the selected item! Don't know how reliable this would be in production code but still worth considering, I think...


    UPDATE. Here is the complete solution if you want to control this behavior via config flag of Combobox:

    Ext.define('My.ComboBox',  {
        extend: 'Ext.form.field.ComboBox',
    
        /**
         * @cfg {Boolean} hideActive=true
         * When true, hides the currently selected value from the dropdown list
         */
        hideActive: true,
    
        /**
         * Internal method that creates the BoundList
         */
        createPicker: function() {
          var picker = this.callParent(arguments);
    
          // honor the hideActive flag
          if(this.hideActive) {
            picker.addCls('x-boundlist-hideactive');
          }
    
          return picker;
        }
    });
    

    Somewhere in your CSS:

    .x-boundlist-hideactive .x-boundlist-selected {
        display: none;
    }
    

    UPDATE 2. Found a UI problem with my approach!

    Hiding the selected item from the dropdown list introduces a quirk to keyboard navigation: though the element is visually hidden, it still exists and Ext will select it when you press UP/DOWN keys. Visually that means that the your selection will disappear at some point and you will have to press UP/DOWN one more time to get it back on the next visible element.

    So far I was unable to find an easy fix for this. My best bet would be to modify itemSelector of the bound list (which is a Data View), setting it to something like .x-boundlist-item:not(.x-boundlist-selected) so the selected element doesn't make it into the query.

    While the selector itself works, it doesn't solve the problem because the View performs this selector query before any additional classes (including the selected item class) get applied to items (this happens in Ext.view.AbstractView.refresh().

    Also, this solution causes misplacement of the dropdown list when it appears above the combobox!

    I had a feeling that my approach was way too easy to work flawlessly :)

    0 讨论(0)
  • 2021-02-15 15:26

    I don't think you have to much options here... maybe you could do something like this:

    Ext.define('Your.company.Combo', {
        extend: 'Ext.form.field.ComboBox',
        alias: 'widget.specialcombo',
    
        /**
        * @cfg {boolean} hideActive
        * True to hide any selected record. Defaults to <tt>true</tt>.
        */
        hideActive: true,
    
        /**
        * @private {Ext.data.Model[]} hideActive
        * A Array of selected records.
        */
    
    
        initComponent: function () {
            this.selectedRecords = [];
    
            this.callParent(arguments);
    
            this.on('select', this.onSelectionChange, this);
        },
    
        /**
        * @private onChangeSelection
        * eventhandler selections
        */
        onSelectionChange: function (me, recs) {
            if(!me.hideActive)
                return;
            // write the current selected back to the store (you need to suspend autoSync if active)
            me.store.add(me.selectedRecords);
            // set the selected as new recordlist
            me.selectedRecords = recs;
            // remove the selected from the store
            me.store.remove(recs);
        }
    });
    

    That example is totally untested. But as the store is mainly bound to the BoundList which is not direct connected to the textfield this should work. You are doing a sort of caching here.

    0 讨论(0)
  • 2021-02-15 15:27

    ExtJS 3 I wrote this answer based on the others. Works great for me, its a little modified from what your looking for though.

    Name.space.name = new Ext.extend(Ext.form.ComboBox, {
        type: 'all',
        oldrec: null,
        store: null,
        constructor: function (config) {
            var me = this;
            if (config.type === 'all') {
                me.store = AllConditionStore;
            } else {
                me.store = ?.?('RuleParameterType');
            }
            config = Ext.apply({
                store: me.store,
                valueField: 'id',
                hideActive: true,
                triggerAction: 'all',
                lazyRender: true,
                allowBlank: false,
                mode: 'local',
                displayField: 'text',
                listeners: {
                    select: function (me, recs, index) {
                        if (me.oldrec !== null)
                            me.store.add(me.oldrec);
                        me.oldrec = recs;
                        // remove the selected from the store
                        me.store.remove(recs);
                        // redo store
                    }
                }
            }, config);
            ?.?.Parameter.superclass.constructor.call(this, config);
        }
    });
    
    0 讨论(0)
提交回复
热议问题