2012-07-04 7 views
14

私は、ストアからデータを取り込んでいるExtJS(4.0.7)GridPanelを持っています。 GridPanelの列に表示される値は、レコード内のデータのタイプによって異なるビューを持つ必要があります。ExtJSでの動的コンポーネントのレンダリングExt.createを使用したGridPanelカラム

最終的な目標は、レコードのtypeプロパティの "double"または "integer"値を持つレコードは、調整可能なスライダーをユーザーに提示し、 "string"タイプは読み込み専用のテキストをレンダリングするだけです。

私はこれを行うカスタムの列を作成しました。レンダラーのタイプを調べ、レンダリングするものを決定します。

私は以下のコードでうまく動作する「文字列」を持っていますが、列内のより複雑なスライダーコントロールを動的に作成してレンダリングする方法に苦労しています。

この単純化された例では、日付コントロール付きでPanelをレンダリングしようとしているように見えますが、それを得ることができるかのように、残りのスライダーを把握できます。本当に私の問題

Ext.define('MyApp.view.MyColumn', { 
    extend: 'Ext.grid.column.Column', 
    alias: ['widget.mycolumn'], 

    stringTemplate: new Ext.XTemplate('code to render {name} for string items'), 

    constructor: function(cfg){ 
     var me = this; 
     me.callParent(arguments); 

     me.renderer = function(value, p, record) { 
      var data = Ext.apply({}, record.data, record.getAssociatedData()); 

      if (data.type == "string") { 
       return me.renderStringFilter(data); 
      } else if (data.type == "double" || data.type == "integer") { 
       return me.renderNumericFilter(data); 
      } else { 
       log("Unknown data.type", data); 

     }; 
    }, 

    renderStringFilter: function(data) { 
     // this works great and does what I want 
     return this.stringTemplate.apply(data); 
    }, 

    renderNumericFilter: function(data) { 

     // ***** How do I get a component I "create" to render 
     // ***** in it's appropriate position in the gridpanel? 
     // what I really want here is a slider with full behavior 
     // this is a placeholder for just trying to "create" something to render 

     var filterPanel = Ext.create('Ext.panel.Panel', { 
      title: 'Filters', 
      items: [{ 
       xtype: 'datefield', 
       fieldLabel: 'date' 
      }], 
      renderTo: Ext.getBody() // this doesn't work 
     }); 
     return filterPanel.html; // this doesn't work 
    } 
}); 

、どのように私Ext.createコンポーネント、およびそれがgridpanelの列にレンダリングすることができますか?

+0

偉大な答えとオプションのためのすべてに感謝を。私ができるならば、私はあなたのポイント(あるいはアップボーディングでできる以上に多くのポイント)を授与したいと思いますが、ジョン・ライスの答えは、レンダラーの明確な遅れなしに私が探していたものに最も近いと思います。 –

答えて

9

これを実現する方法はいくつかあります。グリッド列はExtコンテナではないので、ほかのコンテナコンポーネントと同じように、Extのコンポーネントを任意の構成の一部として子として持つことはできません。 Extコンポーネントをセルに追加するには、ポストグリッドレンダリングロジックが必要です。

このソリューションは、レンダリングされたTDタグに特別なCSSクラスを配置するように、カスタム列のレンダリングを変更します。グリッドビューの準備ができたら、レコードが走査され、適切な特殊な列に対してカスタムクラスが検出されます。見つかった各列にスライダーがレンダリングされます。

以下のコードは、Senchaの例で提供されているext js配列グリッドの変更例です。この変更は、カスタム列レンダラーとTDエレメントへのスライダーのポストグリッドレンダリングでミックスされます。

この例では、実装のアイデアを示すためにSenchaの例を変更しただけです。分離されたビューとコントローラのロジックが欠けています。

これはから変更されています http://docs.sencha.com/ext-js/4-0/#!/example/grid/array-grid.html

Ext.require([ 
    'Ext.grid.*', 
    'Ext.data.*', 
    'Ext.util.*', 
    'Ext.data.Model' 
]); 


Ext.onReady(function() { 

    // sample static data for the store 
    Ext.define('Company', { 
     extend: 'Ext.data.Model', 
     fields: ['name', 'price', 'change', 'pctChange', 'lastUpdated', 'type'] 
    }); 

    var myData = [ 
     ['3m Co',        71.72, 2, 0.03, '9/1/2011', 'integer'], 
     ['Alcoa Inc',       29.01, 4, 1.47, '9/1/2011', 'string'], 
     ['Altria Group Inc',     83.81, 6, 0.34, '9/1/2011', 'string'], 
     ['American Express Company',   52.55, 8, 0.02, '9/1/2011', 'string'], 
     ['American International Group, Inc.', 64.13, 2, 0.49, '9/1/2011', 'integer'], 
     ['AT&T Inc.',       31.61, 4, -1.54, '9/1/2011', 'integer'], 
     ['Boeing Co.',       75.43, 6, 0.71, '9/1/2011', 'string'], 
     ['Caterpillar Inc.',     67.27, 8, 1.39, '9/1/2011', 'integer'], 
     ['Citigroup, Inc.',      49.37, 1, 0.04, '9/1/2011', 'integer'], 
     ['E.I. du Pont de Nemours and Company', 40.48, 3, 1.28, '9/1/2011', 'integer'], 
     ['Exxon Mobil Corp',     68.1, 0, -0.64, '9/1/2011', 'integer'], 
     ['General Electric Company',   34.14, 7, -0.23, '9/1/2011', 'integer'] 
    ]; 

    // create the data store 
    var store = Ext.create('Ext.data.ArrayStore', { 
     model: 'Company', 
     data: myData 
    }); 

    // existing template 
    stringTemplate = new Ext.XTemplate('code to render {name} for string items'); 

    // custom column renderer 
    specialRender = function(value, metadata, record) { 
     var data; 

     data = Ext.apply({}, record.data, record.getAssociatedData()); 

     if (data.type == "string") { 
      return stringTemplate.apply(data);; 
     } else if (data.type == "double" || data.type == "integer") { 
      // add a css selector to the td html class attribute we can use it after grid is ready to render the slider 
      metadata.tdCls = metadata.tdCls + 'slider-target'; 
      return ''; 
     } else { 
      return("Unknown data.type"); 

     } 
    }; 

    // create the Grid 
    grid = Ext.create('Ext.grid.Panel', { 
     rowsWithSliders: {}, 
     store: store, 
     stateful: true, 
     stateId: 'stateGrid', 
     columns: [ 
      { 
       text  : 'Company', 
       flex  : 1, 
       sortable : false, 
       dataIndex: 'name' 
      }, 
      { 
       text  : 'Price', 
       width : 75, 
       sortable : true, 
       renderer : 'usMoney', 
       dataIndex: 'price' 
      }, 
      { 
       text  : 'Change', 
       width : 75, 
       sortable : true, 
       dataIndex: 'change', 
       renderer: specialRender, 
       width: 200 
      }, 
      { 
       text  : '% Change', 
       width : 75, 
       sortable : true, 
       dataIndex: 'pctChange' 
      }, 
      { 
       text  : 'Last Updated', 
       width : 85, 
       sortable : true, 
       renderer : Ext.util.Format.dateRenderer('m/d/Y'), 
       dataIndex: 'lastUpdated' 
      } 
     ], 
     height: 350, 
     width: 600, 
     title: 'Irm Grid Example', 
     renderTo: 'grid-example', 
     viewConfig: { 
      stripeRows: true 
     } 
    }); 

    /** 
    * when the grid view is ready this method will find slider columns and render the slider to them 
    */ 
    onGridViewReady = function() { 
     var recordIdx, 
      colVal, 
      colEl; 

     for (recordIdx = 0; recordIdx < grid.store.getCount(); recordIdx++) { 
      record = grid.store.getAt(recordIdx); 
      sliderHolder = Ext.DomQuery.select('.slider-target', grid.view.getNode(recordIdx)); 
      if (sliderHolder.length) { 
       colEl = sliderHolder[0]; 

       // remove div generated by grid template - alternative is to use a new template in the col 
       colEl.innerHTML = ''; 

       // get the value to be used in the slider from the record and column 
       colVal = record.get('change'); 

       // render the slider - pass in the full record in case record data may be needed by change handlers 
       renderNumericFilter(colEl, colVal, record) 
      } 
     } 

    } 

    // when the grids view is ready, render sliders to it 
    grid.on('viewready', onGridViewReady, this); 

    // modification of existing method but removed from custom column 
    renderNumericFilter = function(el, val, record) { 

     var filterPanel = Ext.widget('slider', { 
      width: 200, 
      value: val, 
      record: record, 
      minValue: 0, 
      maxValue: 10, 
      renderTo: el 
     }); 

    } 

}); 
+2

上記のコードをjsfiddleで見るには、[ここ](http://jsfiddle.net/unKWv/) – GreenGiant

+0

をクリックしてください@GreenGiantは実行可能なバージョンを利用できるようにしていいです –

+1

jsfiddle形式GreenGiantはもう動作しませんが、ここにあります更新されたバージョン:http://jsfiddle.net/unKWv/24/ –

2

はこのような何か試してみてください:

renderNumericFilter: function() { 
    var id = Ext.id(); 
    Ext.defer(function() { 
     Ext.widget('slider', { 
      renderTo: id, 
      width: 200, 
      value: 50, 
      increment: 10, 
      minValue: 0, 
      maxValue: 100, 
     }); 
    }, 50); 
    return Ext.String.format('<div id="{0}"></div>', id); 
} 

をしかし、私はあなたが何をしようとしているものは何でも言わなければならない - それは右の音はありません:)私は、グリッド内のスライダーの束が見えるだろうとは思いませんユーザーには良い。

+0

応答してくれてありがとう!私はこれのUXが最適でないかもしれないことに同意しますが、私はそれが何であるかを見ることができるようにショットを与えるように求められました。私は潜在的に壊れやすい(遅いIEマシンでは)と感じるような "遅延"のようなものを避けることを望んでいましたが、おそらく大丈夫です。私が知りたいことは、文字列以外のものをレンダリングできるようにするために、列(またはグリッドパネル)でオーバーライドする必要があることが最適です。または、何らかの理由でレンダラーのcol&rowパラメーターを使用して、 'defer'コールバックを待たずに直接値を書き込んでください。 –

+0

カラムの 'renderer()'関数をオーバーライドします。 'defer'の使用を避けたいのであれば、あなたが返すこのdivの' render'イベントを見たいかもしれません。 – sha

+0

ですが、 'renderer()'は文字列の返り値を期待して、それを列に描画します。上記の例では、カラムのレンダラーメソッドを実装しています。どのメソッドが実際に 'renderer'メソッドを呼び出しているのか、そして返された文字列をDOMに書き込むのかと思います。 –

7

グリッドの列に小さなチャート(基本的にスパークチャート)をレンダリングする必要があるとき、このようなことをしました。このソリューションはshaと似ていますが、レンダリングチェーンが実際にはないColumnではなく、レンダリングされているコンポーネントにレンダリングを委譲しています。

まず、列クラス:

Ext.define("MyApp.view.Column", { 
    extend: "Ext.grid.column.Column", 

    // ... 

    renderer: function (value, p, record) { 
     var container_id = Ext.id(), 
      container = '<div id="' + container_id + '"></div>'; 

     Ext.create("MyApp.view.Chart", { 
      type: "column", 
      // ... 
      delayedRenderTo: container_id 
     }); 

     return container; 
    } 
}); 

delayedRenderTo設定オプション。 renderToのように、チャートコンポーネントがレンダリングする要素のDOM IDですが、作成時にDOMに存在する必要はありません。その後

コンポーネントクラス:initComponent()中だから、

Ext.define("MyApp.view.Chart", { 
    extend: "Ext.chart.Chart", 

    // ... 

    initComponent: function() { 
     if (this.delayedRenderTo) { 
      this.delayRender(); 
     } 

     this.callParent(); 
    }, 

    delayRender: function() { 
     Ext.TaskManager.start({ 
      scope: this, 
      interval: 100, 
      run: function() { 
       var container = Ext.fly(this.delayedRenderTo); 

       if (container) { 
        this.render(container); 
        return false; 
       } else { 
        return true; 
       } 
      } 
     }); 
    } 
}); 

、我々はレンダリングし、必要に応じていることを準備遅れのために確認してください。それ以外の場合は、通常通りレンダリングされます。

delayRender()関数自体は、指定されたIDを持つ要素の存在を頻繁に(この場合は100ms)チェックするタスクをスケジューリングします。つまり、列がレンダリングされているかどうかをチェックします。そうでない場合、trueを返してタスクを再スケジュールします。そうであれば、コンポーネントをレンダリングし、falseを返してタスクをキャンセルします。

私はフィールドでこれで幸運を祈っています。だから、あなたにとってもうまくいくと思います。


ところで、私はmy own question about ExtJS chartingの一部としてこれを開発していました。そのスレッドは私のパフォーマンステストの結果を持っています。ほとんどのブラウザとOSで3〜4秒でグリッド・カラムに168個のチャート・コンポーネントをレンダリングしていました。私はあなたのスライダーがそれよりはるかに速くレンダリングすると思います。

+2

このアプローチ(とおそらくは同様のこと)の1つは、 'delayedRenderTo' divにレンダリングされるコンポーネントがExtコンテナの観点から「分離」されていることです。つまり、他のコンテナの子アイテムではないため、グリッドが破棄されたときに 'destroy'メソッドが呼び出されることはありません。明示的に行う必要があります。または、グリッドが破棄された後に参照されるコンポーネントや何かがハングアップします。 –