-
1 Sep 2009 1:03 AM #1Sencha - Community Support Team
- Join Date
- Mar 2007
- Location
- The Netherlands
- Posts
- 24,251
- Vote Rating
- 41
ComponentDataView - Ext components inside a dataview or listview
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:
Ext.ux.ComponentListView: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);
Usage example: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);
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 } }] } }] }); });
-
1 Sep 2009 8:20 AM #2
very slick
-
1 Sep 2009 8:45 AM #3
i was just looking for a solution like this! how do i renderTarget to div or input instead of tr?
also it would be nice if the form containing your extension can submit and load the folloing json:
PHP Code:{
first:'John',
last:'Doe',
company:'Some Company',
email:'email@abc.com',
phones:[{
phone:'11111111',type:'mobile'
},{
phone:'22222222',type:'office'
},{
phone:'33333333',type:'home'
}]
}
this is what i'm experimenting with:
PHP Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Complex form test</title>
<link rel='stylesheet' type='text/css' href='http://extjs.com/deploy/dev/resources/css/ext-all.css'/>
<script type="text/javascript" src="http://extjs.com/deploy/dev/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://extjs.com/deploy/dev/ext-all-debug.js"></script>
</head>
<body>
</body>
</html>
<script language="javascript" type="text/javascript">
Ext.QuickTips.init();
</script>
<script type="text/javascript" language="javascript">
Ext.ns('Ext.ux.form');
//MyForm=Ext.extend(Ext.form.FormPanel,{
MyForm=Ext.extend(Ext.Panel,{
initComponent:function(){
Ext.apply(this,{
//baseCls: 'x-plain',
labelWidth: 55,
//url:'save-form.php',
defaultType: 'textfield',
layout:'hbox',
items: [{
fieldLabel: 'Phone',
name: 'phone',
anchor:'100%', // anchor width by percentage
xtype:'textfield'
},{
fieldLabel: 'Type',
name: 'type',
anchor: '100%' // anchor width by percentage
}]
})
MyForm.superclass.initComponent.call(this)
},
initFields : function(){
//var f = this.form;
var formPanel = this;
var fn = function(c){
if(formPanel.isField(c)){
//f.add(c);
}if(c.isFieldWrap){
Ext.applyIf(c, {
labelAlign: c.ownerCt.labelAlign,
labelWidth: c.ownerCt.labelWidth,
itemCls: c.ownerCt.itemCls
});
//f.add(c.field);
}else if(c.doLayout && c != formPanel){
Ext.applyIf(c, {
labelAlign: c.ownerCt.labelAlign,
labelWidth: c.ownerCt.labelWidth,
itemCls: c.ownerCt.itemCls
});
if(c.items){
c.items.each(fn, this);
}
}
};
this.items.each(fn, this);
},
onRender : function(ct, position){
this.initFields();
Ext.FormPanel.superclass.onRender.call(this, ct, position);
//this.form.initEl(this.body);
},
isField : function(c) {
return !!c.setValue && !!c.getValue && !!c.markInvalid && !!c.clearInvalid;
},
setValues : function(values){
if(Ext.isArray(values)){ // array of objects
for(var i = 0, len = values.length; i < len; i++){
var v = values[i];
var f = this.findField(v.id);
if(f){
f.setValue(v.value);
if(this.trackResetOnLoad){
f.originalValue = f.getValue();
}
}
}
}else{ // object hash
var field, id;
for(id in values){
if(!Ext.isFunction(values[id]) && (field = this.findField(id))){
field.setValue(values[id]);
if(this.trackResetOnLoad){
field.originalValue = field.getValue();
}
}
}
}
return this;
},
findField : function(id){
var field = this.items.get(id);
if(!Ext.isObject(field)){
this.items.each(function(f){
if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
field = f;
return false;
}
});
}
return field || null;
}
})
Ext.ux.form.ArrayField = Ext.extend(Ext.form.Field,{
onRender : function(ct, position){
this.panel =new Ext.Panel({
renderTo: ct,
width:230,
height:50,
autoScroll:true,
layout:'vbox',
items:[]
//layout:'vbox',
});
this.el=this.panel.getEl();
//Ext.ux.form.ArrayField.superclass.onRender.call(this, ct, position);
this.hiddenField = Ext.DomHelper.append(this.el,{tag:'input', type:'hidden',name:this.name});
},
setValue:function(val) {
var v = Ext.util.JSON.encode(val);
this.hiddenField.value=v;
//alert(v);
//this.panel.removeAll();
for (var i=0;i<val.length;i++){
var f = new MyForm()
this.panel.add(f)
this.panel.doLayout();
f.setValues(val[i])
}
},
getValues:function(){
}
});
// register xtype
Ext.reg('arrayfield', Ext.ux.form.ArrayField);
</script>
<script type="text/javascript">
Ext.onReady(function(){
var f = new Ext.FormPanel({
labelWidth: 75,
url:'save-form.php',
frame:true,
title: 'Simple Form',
bodyStyle:'padding:5px 5px 0',
width: 350,
defaults: {width: 230},
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank:false
},{
fieldLabel: 'Last Name',
name: 'last'
},{
fieldLabel: 'Company',
name: 'company'
}, {
fieldLabel: 'Email',
name: 'email',
vtype:'email'
}, new Ext.form.TimeField({
fieldLabel: 'Time',
name: 'time',
minValue: '8:00am',
maxValue: '6:00pm'
}),
this.a=new Ext.ux.form.ArrayField({name:'items',form:MyForm})
],
buttons: [{
text: 'Save',
handler: function(){
var i=0;
},
scope:this
},{
text: 'Cancel'
}]
});
f.render(document.body);
var rec={}
rec.data={
first:'John',
last:'Doe',
company:'Some Company',
email:'email@abc.com',
items:[{
phone:'11111111',type:'mobile'
},{
phone:'22222222',type:'office'
},{
phone:'33333333',type:'home'
}]
}
f.form.loadRecord(rec);
})
</script>
-
1 Sep 2009 9:26 AM #4
i replied earlier but somehow it had to be approved by the moderator. any idea why is it so?
-
16 Oct 2009 7:40 PM #5
onDestroy error
onDestroy error
I had to patch onDestroy with these:
Code:Ext.override(Ext.ux.ComponentListView, { onDestroy : function(){ Ext.ux.ComponentListView.superclass.onDestroy.call(this); Ext.destroy(this.components); this.components = []; }, }); Ext.override(Ext.ux.ComponentDataView, { onDestroy : function(){ Ext.ux.ComponentDataView.superclass.onDestroy.call(this); Ext.destroy(this.components); this.components = []; }, });
-
18 Mar 2010 9:09 PM #6
-
18 Mar 2010 10:24 PM #7Sencha - Community Support Team
- Join Date
- Mar 2007
- Location
- The Netherlands
- Posts
- 24,251
- Vote Rating
- 41
Are you sure the combobox store is loaded when the dataview is rendered?
(also see this feature request)
-
19 Mar 2010 12:05 AM #8
This is really nice Condor. Could it be refactored as a layout class?
Search the forum: http://www.google.com/coop/cse?cx=01...%3Az7of1ufqccu
Read the docs too: http://extjs.com/deploy/dev/docs/
Scope: http://extjs.com/forum/showthread.ph...642#post257642
-
19 Mar 2010 12:47 AM #9Sencha - Community Support Team
- Join Date
- Mar 2007
- Location
- The Netherlands
- Posts
- 24,251
- Vote Rating
- 41
-
19 Mar 2010 1:32 AM #10
Oh! I'd forgotten all about it!

I think it ought to be part of the base library. HTML as scaffolding round Components is really useful for adding structure or hanging CSS styles off.Search the forum: http://www.google.com/coop/cse?cx=01...%3Az7of1ufqccu
Read the docs too: http://extjs.com/deploy/dev/docs/
Scope: http://extjs.com/forum/showthread.ph...642#post257642


Reply With Quote