2012-07-04 8 views
14

Bir mağazadan doldurduğum bir ExtJS (4.0.7) GridPanel sahibim. GridPanel'in sütununda görüntülediğim değerlerin, kayıttaki verilerin türüne bağlı olarak farklı bir görünüme sahip olması gerekir.ExtJS 4 GridPanel Sütun Ext.create ile dinamik bileşenleri oluşturma

Nihai hedef, kaydın type özelliğinin "çift" veya "tamsayı" değerine sahip kayıtlarının, kullanıcıya ayarlayabilecekleri bir kaydırma çubuğu sunması ve "dize" türünün salt okunur metin oluşturmasıdır.

Bunu yapmak için özel bir sütun oluşturdum. Oluşturucudaki türü inceler ve ne oluşturulacağını belirler.

Aşağıdaki kodla birlikte çalışan "dize" sorunum var, ancak dinamik olarak sütunda daha karmaşık kaydırıcı denetimini oluşturabilir ve oluşturabilirim.

Bu basitleştirilmiş örnek, bir Panel içinde bir tarih denetimiyle render etmeye çalışıyorum, sanki o şeyi başarabiliyormuş gibi, kayan öğelerin kalanını anlayabiliyorum. Gerçekten is Sorunum

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

, nasıl Ext.create bir bileşenidir ve bu gridpanel bir sütuna oluşturulmasını sağlayabilirsiniz? Böyle

+0

teşekkür:

Bu

den değiştirilir. Yapabilseydim tüm puanlarınızı (veya elden çıkarabildiğimden daha fazla puan) verirdim, ama sanırım John Rice'ın cevabı, işleyicide açık gecikme olmadan aradığımın en yakın cevabı. –

cevap

9

Bunu başardığımı görmenin birkaç yolu vardır. Izgara sütunu bir Ext konteyner olmadığı için, diğer konteyner bileşenlerinin yapabildiği şekilde herhangi bir konfigürasyonun parçası olarak çocuklar olarak Ext bileşenlerine sahip olamaz. Hücrelere Ext bileşenlerini eklemek için grid oluşturma mantığı gereklidir.

Bu çözüm, özel sütun oluşturmanızı değiştirerek işlenen TD etiketine özel bir css sınıfı yerleştirir. Izgara görünümü hazır olduktan sonra kayıtlar geçilir ve özel sınıf uygun özel sütunlar için bulunur. Bulunan her sütuna bir kaydırıcı oluşturulur.

Aşağıdaki kod Sencha örneklerinde sağlanan ext js array grid örneğinin değiştirilmiş bir sürümüdür. Modifikasyon, özel sütun oluşturucuda ve sürgülerin TD elemanlarına kılavuz sonrası işlenmesinde karışır. Bu örnek yalnızca uygulama fikirlerini göstermek için Sencha örneğinin yeterince değiştirilmesini içerir. Ayrı görünüm ve denetleyici mantığı yoktur. Büyük yanıtlar ve seçenekleri için herkese 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

Yukarıdaki kodu jsfiddle olarak görmek için, [burada] tıklayın (http://jsfiddle.net/unKWv/) – GreenGiant

+0

+1 @GreenGiant çalışan sürümün şu anki haliyle kullanıma sunulması güzeldi –

+1

jsfiddle formu GreenGiant artık çalışmıyor ama burada güncelleştirilmiş bir sürüm: http://jsfiddle.net/unKWv/24/ –

2

deneyin şey:

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

Ama yapmaya çalıştığını ne söylemeliyim - ızgara bakacağız içeride doğru gelmiyor :) Ben sürgü bir demet sanmıyorum kullanıcı için iyi.

+0

Yanıt için teşekkürler! Bunun UX'inin optimal olamayacağına katılıyorum, ama ona bir şans vermem istendi, böylece neye benzediğini görebiliyoruz. Potansiyel olarak hassas (özellikle yavaş IE makinelerinde) hissedilen bir 'defer' gibi bir şeyden kaçınmayı umuyordum, ama belki sorun değil. Optimal olarak, bilmek istediğim, bir dizeden başka bir şey oluşturmama izin vermek için hangi sütunda (veya gridpanel) geçersiz kılmanın gerekli yöntemidir. Ya da bir şekilde 'erteleme' geri çağrısını beklemeden değeri doğrudan yazmak için işleyici üzerindeki sütun ve satır parametrelerini kullanın. –

+0

Sütun için renderer() işlevini geçersiz kılarsınız. Eğer 'defer' kullanmaktan kaçınmak istiyorsanız - döndüğünüz bu div için 'render' olayına bakmak isteyebilirsiniz. – sha

+0

ancak renderer(), bir dize dönüş değeri bekler ve sonra bunu sütuna verir. Yukarıdaki örneğimde sütunun "renderer" yöntemini uyguluyorum. Hangi yöntemin aslında 'renderer' yöntemini çağırdığını ve sonra döndürülen dizeyi alıp DOM'a yazdığını merak ediyorum. –

7

Izgara sütununda küçük bir grafik (esas olarak kıvılcım grafiği) oluşturmam gerektiğinde böyle bir şey yaptım. Bu çözüm, sha'lere benzer, ancak daha sağlamdır ve render işlemini gerçekten bir render zincirine sahip olmayan Column'dan ziyade işlenen bileşene aktarır.

İlk olarak, kolon sınıfı:

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

Not delayedRenderTo yapılandırma seçeneği. Tıpkı renderTo gibi, bu, grafik bileşeninin oluşturulacağı öğenin DOM Kimliği olacaktır; bunun dışında, oluşturma zamanında DOM'da bulunması gerekmiyor.

Sonra bileşen sınıfı:

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

Yani initComponent() sırasında, biz işlemek ve gerekirse o hazırlamak gecikmeli kontrol edin. Aksi takdirde, normal olarak işler.

delayRender() işlevinin kendisi, her bir işlevi (örneğin bu durumda 100ms), belirli bir kimliğe sahip olan bir öğenin varlığı için (yani, sütunun işlenip işlenmediğini kontrol etmek için) sık sık kontrol etmek üzere bir görev zamanlar. Değilse, görevi yeniden zamanlamak için true değerini döndürür. Öyleyse, bileşeni işler ve görevi iptal etmek için false değerini döndürür.

Bu alanda iyi şanslar elde ettik, umarım sizin için de çalışır. Bu arada


, ben my own question about ExtJS charting cevap vermenin bir parçası olarak bu geliştiriyordu. Bu iş parçacığı benim performans testimin sonuçları.Çoğu tarayıcıda ve işletim sisteminde 3-4'lü grid sütunlarında 168 grafik bileşeni oluşturuyordum. Kaydırıcıların bundan daha hızlı olacağını hayal ediyorum.

+2

Bu yaklaşıma sahip bir tane (ve muhtemelen de sha's da olduğu gibi) 'delayedRenderTo' divine işlenen bileşenin Ext konteyner perspektifinden 'ayrılmış' olmasıdır. Başka bir deyişle, başka bir kabın bir alt öğesi değil, dolayısıyla 'yok etme' yöntemi, ızgara yok olduğunda çağrılmayacak; Bunu açıkça yapmanız gerekir, ya da bileşen ve ızgaraya zarar verildikten sonra referans vereceği herhangi bir şey asılır. –