8

我正在使用 ExtJS 4 并寻找一种方法可以从组合的下拉列表中隐藏当前选定的值?

所以代替这个(组合框中当前选择的“阿拉斯加”):

默认组合框行为

我希望值列表如下所示:

在此处输入图像描述

在我的情况下,组合框不可编辑(即您不能输入任意值),我认为两次显示所选值没有多大意义:一次在输入字段中,一次在下拉列表中。我已经看到选择了什么,我希望下拉列表只显示我可以选择的其他选项。

到目前为止,我还没有看到一个简单的方法来做到这一点。可能最好的起点是过滤组合框商店,但组合框使用自己的过滤器来实现实时搜索功能。

有人考虑过这个问题吗?我在尝试做一些奇怪的事情吗?我很惊讶我找不到任何相关的主题。

4

5 回答 5

6

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.

于 2012-09-04T19:18:36.817 回答
4

我想出了另一个看起来更简单的解决方案,并且快速测试显示没有副作用:

我们可以保持 Combobox 逻辑不变,但只需通过 CSS 隐藏所选项目:

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

瞧,我们看不到所选项目!不知道这在生产代码中有多可靠,但我认为仍然值得考虑......


更新。如果您想通过 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;
    }
});

在您的 CSS 中的某处:

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

更新 2. 发现我的方法存在 UI 问题!

从下拉列表中隐藏选定的项目会给键盘导航带来一个怪癖:虽然该元素在视觉上是隐藏的,但它仍然存在,并且当您按下 UP/DOWN 键时,Ext 会选择它。从视觉上看,这意味着您的选择将在某个时候消失,您必须再按一次 UP/DOWN 才能将其恢复到下一个可见元素上。

到目前为止,我无法找到一个简单的解决方法。我最好的选择是修改itemSelector绑定列表(这是一个数据视图),将其设置为类似.x-boundlist-item:not(.x-boundlist-selected)这样的内容,以便所选元素不会进入查询。

虽然选择器本身可以工作,但它并不能解决问题,因为视图会在任何其他类(包括所选项目类)应用于项目之前执行此选择器查询(这发生在Ext.view.AbstractView.refresh()中。

此外,当下拉列表出现在组合框上方时,此解决方案会导致错位!

我有一种感觉,我的方法太容易完美地工作了:)

于 2012-09-06T07:19:05.650 回答
2

我最终使用了@sra 解决方案的修改版本:

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

});

“隐藏”逻辑是相同的,只是我在setValue方法中执行它以确保它在以编程方式设置组合的值时也可以工作,包括使用值初始化组合框的情况。

UPD另外,看起来store.add(this.selectedRecords);必须在之前 this.callParent(arguments);调用,否则如果我们尝试设置相同的值两次,组合框会表现得很奇怪(它根本不会在商店中找到活动记录,因为我们删除了它,所以它会重置为空白)。我暂停了商店的事件,以防止组合框在我对选定记录的操作过程中尝试与其下拉列表同步而引起的一些怪癖,并'refresh'在我完成后手动触发商店的事件,以便最终更新列表。这可能会对性能产生影响,但到目前为止我不知道更好的解决方案。

于 2012-10-19T10:30:36.090 回答
2

ExtJS 3 我根据其他人写了这个答案。对我来说效果很好,但它与您所寻找的有所不同。

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);
    }
});
于 2013-07-31T23:51:23.420 回答
0

所以我使用了@sra 的解决方案,但稍作修改,将内容添加到以下正确位置if(!me.hideActive)

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

这样你就不会将它们添加到底部。我知道这是一个旧帖子,但我希望它可以帮助人们寻找解决方案。

于 2014-08-26T19:00:50.760 回答