ComponentDataView - Ext components inside a dataview or listview
DataView and ListView are very useful to render store based data as HTML. This extension adds the ability to include Ext components in the HTML without the need to keep track of them (e.g. you won't get a memory leak when you update or delete a record).
It also supports automatically getting and setting the value from the store if the component is an Ext.form.Field.
Ext.ux.ComponentDataView:
Code:
Ext.ns('Ext.ux');
Ext.ux.ComponentDataView = Ext.extend(Ext.DataView, {
defaultType: 'textfield',
initComponent : function(){
Ext.ux.ComponentDataView.superclass.initComponent.call(this);
this.components = [];
},
refresh : function(){
Ext.destroy(this.components);
this.components = [];
Ext.ux.ComponentDataView.superclass.refresh.call(this);
this.renderItems(0, this.store.getCount() - 1);
},
onUpdate : function(ds, record){
var index = ds.indexOf(record);
if(index > -1){
this.destroyItems(index);
}
Ext.ux.ComponentDataView.superclass.onUpdate.apply(this, arguments);
if(index > -1){
this.renderItems(index, index);
}
},
onAdd : function(ds, records, index){
var count = this.all.getCount();
Ext.ux.ComponentDataView.superclass.onAdd.apply(this, arguments);
if(count !== 0){
this.renderItems(index, index + records.length - 1);
}
},
onRemove : function(ds, record, index){
this.destroyItems(index);
Ext.ux.ComponentDataView.superclass.onRemove.apply(this, arguments);
},
onDestroy : function(){
Ext.ux.ComponentDataView.onDestroy.call(this);
Ext.destroy(this.components);
this.components = [];
},
renderItems : function(startIndex, endIndex){
var ns = this.all.elements;
var args = [startIndex, 0];
for(var i = startIndex; i <= endIndex; i++){
var r = args[args.length] = [];
for(var items = this.items, j = 0, len = items.length, c; j < len; j++){
c = items[j].render ?
c = items[j].cloneConfig() :
Ext.create(items[j], this.defaultType);
r[j] = c;
if(c.renderTarget){
c.render(Ext.DomQuery.selectNode(c.renderTarget, ns[i]));
}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, ns[i]));
}else{
c.render(ns[i]);
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}
}
}
this.components.splice.apply(this.components, args);
},
destroyItems : function(index){
Ext.destroy(this.components[index]);
this.components.splice(index, 1);
}
});
Ext.reg('compdataview', Ext.ux.ComponentDataView);
Ext.ux.ComponentListView:
Code:
Ext.ux.ComponentListView = Ext.extend(Ext.ListView, {
defaultType: 'textfield',
initComponent : function(){
Ext.ux.ComponentListView.superclass.initComponent.call(this);
this.components = [];
},
refresh : function(){
Ext.destroy(this.components);
this.components = [];
Ext.ux.ComponentListView.superclass.refresh.apply(this, arguments);
this.renderItems(0, this.store.getCount() - 1);
},
onUpdate : function(ds, record){
var index = ds.indexOf(record);
if(index > -1){
this.destroyItems(index);
}
Ext.ux.ComponentListView.superclass.onUpdate.apply(this, arguments);
if(index > -1){
this.renderItems(index, index);
}
},
onAdd : function(ds, records, index){
var count = this.all.getCount();
Ext.ux.ComponentListView.superclass.onAdd.apply(this, arguments);
if(count !== 0){
this.renderItems(index, index + records.length - 1);
}
},
onRemove : function(ds, record, index){
this.destroyItems(index);
Ext.ux.ComponentListView.superclass.onRemove.apply(this, arguments);
},
onDestroy : function(){
Ext.ux.ComponentDataView.onDestroy.call(this);
Ext.destroy(this.components);
this.components = [];
},
renderItems : function(startIndex, endIndex){
var ns = this.all.elements;
var args = [startIndex, 0];
for(var i = startIndex; i <= endIndex; i++){
var r = args[args.length] = [];
for(var columns = this.columns, j = 0, len = columns.length, c; j < len; j++){
var component = columns[j].component;
c = component.render ?
c = component.cloneConfig() :
Ext.create(component, this.defaultType);
r[j] = c;
var node = ns[i].getElementsByTagName('dt')[j].firstChild;
if(c.renderTarget){
c.render(Ext.DomQuery.selectNode(c.renderTarget, node));
}else if(c.applyTarget){
c.applyToMarkup(Ext.DomQuery.selectNode(c.applyTarget, node));
}else{
c.render(node);
}
if(c.applyValue === true){
c.applyValue = columns[j].dataIndex;
}
if(Ext.isFunction(c.setValue) && c.applyValue){
c.setValue(this.store.getAt(i).get(c.applyValue));
c.on('blur', function(f){
this.store.getAt(this.index).data[this.dataIndex] = f.getValue();
}, {store: this.store, index: i, dataIndex: c.applyValue});
}
}
}
this.components.splice.apply(this.components, args);
},
destroyItems : function(index){
Ext.destroy(this.components[index]);
this.components.splice(index, 1);
}
});
Ext.reg('complistview', Ext.ux.ComponentListView);
Usage example:
Code:
Ext.onReady(function() {
new Ext.Viewport({
layout: 'hbox',
layoutConfig: {
align: 'stretch'
},
defaults: {
flex: 1
},
items: [{
title: 'ComponentDataView example',
items: {
xtype: 'compdataview',
store: [[1, 'One'], [2, 'Two'], [3, 'Three']],
itemSelector: 'tbody tr',
tpl: '<table><thead><tr><td>Value</td><td>Text</td></tr></thead><tbody><tpl for="."><tr><td></td><td></td></tr></tpl></tbody></table>',
items: [{
xtype: 'numberfield',
minValue: 0,
maxValue: 100,
renderTarget: 'td:nth(1)',
applyValue: 'field1'
},{
allowBlank: false,
renderTarget: 'td:nth(2)',
applyValue: 'field2'
}]
}
},{
title: 'ComponentListView example',
items: {
xtype: 'complistview',
store: [[1, 'One'], [2, 'Two'], [3, 'Three']],
columns: [{
header: 'Value',
width: .5,
dataIndex: 'field1',
tpl: ' ',
component: {
xtype: 'numberfield',
minValue: 0,
maxValue: 100,
applyValue: true
}
},{
header: 'Text',
width: .5,
dataIndex: 'field2',
tpl: ' ',
component: {
allowBlank: false,
applyValue: true
}
}]
}
}]
});
});