6

しばらく頭を悩ませていたExtJsプロジェクトを開始しましたが、これは私を困惑させています。

リモート JSON ストアを使用してユーザーを一覧表示する Ext.form.ComboBox があります。ドロップダウンにリストされているように、XTemplate を使用してユーザーをフォーマットします。

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

ドロップダウンを展開すると、ユーザーが正しく一覧表示されます。

ジョン・スミス (jsmith@company.com)

ジョン・フォード (jford@company.com)

ただし、ユーザーをクリックすると、コンボ ボックスの内容が valueField プロパティ ('firstname') に変更されます。

問題:

  1. John を表示する代わりに、コンボ ボックスに John Smith (jsmith@company.com) を表示したいと思います。

  2. 2 つの John (John Smith と John Ford) があり、フォームが読み込まれると、ExtJs ロジックはリストで最初に見つかった John と照合し、フィールドの値を最初に一致した John に変更します。

例: ジョン・スミス (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);
4

2 に答える 2

12

問題 1 に関しては、適切なカスタム表示フィールドを取得する最善の方法は、Store が使用する Ext.data.Record 定義で生成されたフィールドを使用することです。こうすることで、表示フィールドを作成するためにアクセスする完全なレコードを取得し、1 つのフィールドだけに限定されません。Sencha が Ext4 に移行しているため、3.x の例をオンラインで見つけることはできませんがexamples/form、ExtJS ダウンロードのディレクトリでこの例を見つけることができます。ここでは、ExtJS コンボの例 ( examples/form/combo.js)の 1 つを変更しました。

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 docsconvertでドキュメントを見つけることができます。

idProperty問題 2 に関しては、JsonStore や ArrayStore などのコンビニエンス ストア + リーダー コンボのいずれかを使用している場合は、Ext.data.Reader またはストアに を設定する必要がある場合があります。idProperty一意の識別子を探すフィールドを Ext に指示します。idPropertyを持っていないか、一意でないものを選択すると、あらゆる種類の奇妙な動作が発生する可能性があります。そのためのドキュメントはこちらです。

于 2011-05-03T02:34:26.013 に答える
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>'
)
于 2015-01-30T07:15:06.473 に答える