在ExtJs 3.3组合框中显示多个字段 [英] Display multiple fields in ExtJs 3.3 Combo box

查看:131
本文介绍了在ExtJs 3.3组合框中显示多个字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经开了一个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。


例如:
John Smith(ID = 1)
John Ford(ID = 2)



用户选择约翰·福特,约翰在组合框单击组合菜单项后,将出现在组合框中,并将user_id = 2写入数据库。



当我重新加载页面时,名称John与数据库匹配(第一个列表条目)匹配,如果操作员不手动更改选择下拉对话框,然后选择John Smith,并将user_id = 1写入数据库(用户保存表单时)。



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



〜 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~电子邮件地址(因为我们可能会有数百个用户进行搜索)。



我继承的ComboBox元素:

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

filterKeys:[],

//注意:这覆盖Ext 3.3中的标准doQuery函数
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();
}
}
},

/ **
*过滤商店的自定义功能
* /
filterFn: function(rec,id,q){

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

//如果没有应用过滤器,则不显示结果
if(parts.length == 0){
return false;
}

//迭代用户字符串的每个部分
//他们必须至少部分匹配一个filterKeys
/ /(ie id,email,firstname等)
for(i = 0; i< parts.length; i ++){
var foundPart = false;

//为此搜索片段(即'@gmai')创建一个RegExp对象
var matcher = this.store.data.createValueMatcher(parts [i],true);

//搜索直到匹配此记录的一个键
for(j = 0; j< this.filterKeys.length; j ++){
if(matcher。 test(rec.get(this.filterKeys [j]))){
foundPart = true;
break;
}
}

//如果没有匹配此部分的记录字段,
//记录不匹配(return false)
if(foundPart == false){
return false;
}
}
返回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);


解决方案

关于问题#1,我找到的最好的方法获取良好的自定义显示字段是在商店使用的Ext.data.Record定义中使用生成的字段。这样,您可以获得完整的记录来创建您的显示字段,而不仅限于一个字段。我现在找不到Sencha正在进行Ext4的3.x示例,但是您可以在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]}
//显示为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:'选择一个状态...',
selectOnFocus:true,
applyTo:'local -states'
});

现在,组合显示的值如 Texas - TX 或任何你有 convert 输出。您可以在 convert 的文档.data.Fieldrel =noreferrer> Ext.data.Field docs



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


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

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:

'<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 (jsmith@company.com)

John Ford (jford@company.com)

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

Issues:

  1. Instead of showing John, I'd like the combo box to show: John Smith (jsmith@company.com).

  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.

For example: John Smith (ID = 1) John Ford (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.

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).

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.

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

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:

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

解决方案

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/form directory of your ExtJS download. Here I've modified one of the ExtJS combo examples (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 convert output. You can find documentation for convert in the Ext.data.Field docs.

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

这篇关于在ExtJs 3.3组合框中显示多个字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆