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

时间:2011-05-02 20:45:17

标签: javascript extjs combobox extjs3

我已经打开了一个ExtJs项目,我已经有一段时间不知道了,这让我很困惑。

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

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

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

John Smith(jsmith@company.com)

John Ford(jford@company.com)

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

的问题:

  1. 我不想展示John,而是想要显示组合框:John Smith(jsmith@company.com)。

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

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

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

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

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

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

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

    我继承的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);
    

2 个答案:

答案 0 :(得分:10)

关于问题#1,我发现获得良好自定义显示字段的最佳方法是使用Store使用的Ext.data.Record定义中的生成字段。这样,您可以获得完整记录来访问以创建显示字段,并且不仅限于一个字段。我现在无法在线找到3.x示例Sencha正在转向Ext4,但您可以在ExtJS下载的examples/form目录中找到此示例。在这里,我修改了一个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'
});

现在,组合会显示Texas - TX之类的值,或者输出的任何内容convert。您可以在Ext.data.Field docs中找到convert的文档。

对于问题#2,如果您正在使用JsonStore或ArrayStore等方便的商店+阅读器组合之一,则可能需要为Ext.data.Reader或商店设置idPropertyidProperty告诉Ext哪个字段要查找唯一标识符。如果您没有idProperty或者您选择的不是唯一的,那么您可以获得各种奇怪的行为。文档为here

答案 1 :(得分:2)

您只需将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>'
)