javascript 在 ExtJs 3.3 组合框中显示多个字段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5862267/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 18:35:44  来源:igfitidea点击:

Display multiple fields in ExtJs 3.3 Combo box

javascriptextjscomboboxextjs3

提问by Duncan

I've opened up an ExtJs project that I've not had my head in for some time, and this is baffling me.

我打开了一个 ExtJs 项目,我已经有一段时间没有考虑过这个项目了,这让我很困惑。

I've an Ext.form.ComboBox that uses a remote JSON store to list users. I use an XTemplate to format the users as listed in the drop down:

我有一个 Ext.form.ComboBox,它使用远程 JSON 存储来列出用户。我使用 XTemplate 来格式化下拉列表中列出的用户:

'<tpl for="."><div class="x-combo-list-item">',
'{firstname} {lastname} ({email})',
'</div></tpl>'

When I expand the drop down, I see my users listed correctly:

当我展开下拉菜单时,我看到我的用户被正确列出:

John Smith ([email protected])

约翰·史密斯 ([email protected])

John Ford ([email protected])

约翰福特 ([email protected])

However when I click on a user, the combo box contents change to the valueField property ('firstname') which you would expect.

但是,当我单击用户时,组合框的内容会更改为您期望的 valueField 属性('firstname')。

Issues:

问题:

  1. Instead of showing John, I'd like the combo box to show: John Smith ([email protected]).

  2. When I have two John's (John Smith and John Ford) and the form loads, the ExtJs logic matches against the first John it finds in the list and changes the value of the field to the first John it matches against.

  1. 我不想显示 John,而是希望组合框显示:John Smith ([email protected])。

  2. 当我有两个 John 的(John Smith 和 John Ford)并且表单加载时,ExtJs 逻辑匹配它在列表中找到的第一个 John,并将该字段的值更改为它匹配的第一个 John。

For example: John Smith (ID = 1) John Ford (ID = 2)

例如:约翰史密斯 (ID = 1) 约翰福特 (ID = 2)

The user chooses John Ford, and "John" appears in the combo box after they've clicked the combo menu item, and user_id = 2 is written to the database.

用户选择 John Ford,单击组合菜单项后,“John”出现在组合框中,并将 user_id = 2 写入数据库。

When I reload the page however, the name "John" is matched (loaded from the database) to the first list entry, and if the operator does not manually change the selection in the drop down dialog, then John Smith is selected and user_id = 1 is now written to the database (when the user saves the form).

然而,当我重新加载页面时,名称“John”与第一个列表条目匹配(从数据库加载),如果操作员没有手动更改下拉对话框中的选择,则选择 John Smith 并且 user_id = 1 现在写入数据库(当用户保存表单时)。

Any input would be much appreciated. My gut tells me there should be a couple of hooks during load and post list click that will allow me to manipulate what is written to the innerHTML element of the element.

任何输入将不胜感激。我的直觉告诉我在加载和发布列表点击期间应该有几个钩子,这将允许我操纵写入元素的 innerHTML 元素的内容。

~~~~~~~~~~~~~

~~~~~~~~~~~~~

Note: I've inheriting from a custom class which allows me to type ahead query against, firstname, lastname and email address (as we may potentially have hundreds of users to search against).

注意:我继承了一个自定义类,它允许我预先输入查询,名字、姓氏和电子邮件地址(因为我们可能有数百个用户要搜索)。

The ComboBox element I'm inheriting from:

我继承的 ComboBox 元素:

CW.form.CustomComboBox = Ext.extend( Ext.form.ComboBox, {

filterKeys:[],

// Note: This overrides the standard doQuery function in Ext 3.3
doQuery: function(q, forceAll){

    q = Ext.isEmpty(q) ? '' : q;
    var qe = {
        query: q,
        forceAll: forceAll,
        combo: this,
        cancel:false
    };
    if(this.fireEvent('beforequery', qe)===false || qe.cancel){
        return false;
    }
    q = qe.query;
    forceAll = qe.forceAll;
    if(forceAll === true || (q.length >= this.minChars)){
        if(this.lastQuery !== q){
            this.lastQuery = q;
            if(this.mode == 'local'){
                this.selectedIndex = -1;
                if(forceAll){
                    this.store.clearFilter();
                }else{
                    // this.store.filter(this.displayField, q);
                    this.store.filterBy( function(rec,id){
                        return this.filterFn(rec,id,q);
                    }, this );
                }
                this.onLoad();
            }else{
                this.store.baseParams[this.queryParam] = q;
                this.store.load({
                    params: this.getParams(q)
                });
                this.expand();
            }
        }else{
            this.selectedIndex = -1;
            this.onLoad();
        }
    }
},

/**
 * Custom function for filtering the store
 */
filterFn: function(rec, id, q ){

    // var filterKeys = ['id', 'firstname', 'lastname', 'email'];
    var parts = q.split(' ');

    // If no filter applied then show no results
    if(parts.length == 0){
        return false;
    }

    // Iterate through each of the parts of the user string
    // They must all match, at least in part, one of the filterKeys
    // (i.e. id, email, firstname, etc.)
    for(i=0; i<parts.length;i++){
        var foundPart = false;

        // Create a RegExp object for this search snippet (i.e. '@gmai')
        var matcher = this.store.data.createValueMatcher(parts[i] , true);

        // Search until this matches one of the keys for this record
        for(j=0;j<this.filterKeys.length; j++){
            if(matcher.test(rec.get(this.filterKeys[j]))){
                foundPart = true;
                break;
            }
        }

        // If there are no fields of the record matching this part,
        // the record does not match (return false)
        if( foundPart == false ){
            return false;
        }
    }
    return true;

},

initComponent: function(){

    Ext.applyIf(this,{
        listeners:{
            beforequery: function(qe){
                    delete qe.combo.lastQuery;
                    return true;
                }          
            }
    });

    if(this.filterKeys.length == 0){
        this.filterKeys = [this.displayField];
    }

    CW.form.CustomComboBox.superclass.initComponent.call(this);


}
});
Ext.reg('custom-combo', CW.form.CustomComboBox);

回答by wes

Regarding issue #1, the best way I have found to get good custom display fields is to use generated fields in the Ext.data.Record definition that the Store uses. That way you get the full record to access to create your display field and aren't limited to just one field. I can't find the 3.x examples online now that Sencha is moving on to Ext4, but you can find this example in the examples/formdirectory of your ExtJS download. Here I've modified one of the ExtJS combo examples (examples/form/combo.js):

关于问题#1,我发现获得良好自定义显示字段的最佳方法是在商店使用的 Ext.data.Record 定义中使用生成的字段。这样您就可以获得完整的记录来创建您的显示字段,而不仅限于一个字段。现在 Sencha 正在转向 Ext4,我在网上找不到 3.x 示例,但是您可以在examples/formExtJS 下载目录中找到此示例。在这里,我修改了 ExtJS 组合示例之一 ( examples/form/combo.js):

var store = new Ext.data.ArrayStore({
    fields: ['abbr', 'state', 'nick', { 
       name: 'display', 
       convert: function(v, rec) { return rec[1] +' - '+ rec[0] }
       // display looks like 'Texas - TX' 
    }],
    data : Ext.exampledata.states // from states.js
});
var combo = new Ext.form.ComboBox({
    store: store,
    displayField:'display',
    typeAhead: true,
    mode: 'local',
    forceSelection: true,
    triggerAction: 'all',
    emptyText:'Select a state...',
    selectOnFocus:true,
    applyTo: 'local-states'
});

And now the combo displays values like Texas - TX, or whatever you have convertoutput. You can find documentation for convertin the Ext.data.Field docs.

现在组合显示值,如Texas - TX,或任何你有convert输出。您可以convertExt.data.Field 文档中找到相关文档

As for issue #2, you may need to set the idPropertyfor your Ext.data.Reader or your store if you're using one of the convenient store + reader combos like JsonStore or ArrayStore. idPropertytells Ext which field to look for for a unique identifier. You can get all kinds of weird behavior if you don't have an idPropertyor you choose one that isn't unique. Docs for that are here.

至于问题 #2,idProperty如果您使用便利的商店 + 阅读器组合(如 JsonStore 或 ArrayStore)之一,则可能需要为您的 Ext.data.Reader 或您的商店设置。 idProperty告诉 Ext 寻找唯一标识符的字段。如果你没有idProperty或者你选择了一个不是独一无二的,你会得到各种奇怪的行为。文档在这里

回答by Akshat M

You just need to replace your displayField with the below code

你只需要用下面的代码替换你的 displayField

tpl: Ext.create('Ext.XTemplate',
    '<tpl for=".">',
        '<div class="x-boundlist-item">{firstName} {lastName} {email}</div>',
    '</tpl>'
),
// template for the content inside text field
displayTpl: Ext.create('Ext.XTemplate',
    '<tpl for=".">',
        'firstName} {lastName} {email}',
    '</tpl>'
)